<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-29735925</id><updated>2012-02-16T16:56:32.066-03:00</updated><category term='Unix'/><category term='Scripting'/><category term='Shell'/><category term='Curiosidad'/><category term='OLAP'/><category term='python'/><category term='Programa'/><category term='Javascript'/><category term='Programación'/><category term='Seguridad'/><category term='algoritmos'/><category term='Cultura Libre'/><category term='Humor'/><category term='Reflexión y Opinión'/><category term='Tcl/Tk'/><category term='Análisis y Diseño'/><category term='Java'/><category term='Videojuegos'/><category term='Lenguaje C'/><title type='text'>Programación Bizarra</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>56</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-29735925.post-4267779693891515557</id><published>2011-07-04T18:08:00.003-03:00</published><updated>2011-07-04T18:13:32.144-03:00</updated><title type='text'>250 caracteres</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://lh5.googleusercontent.com/-4aDaWO7mqxQ/ThIsW9m7ycI/AAAAAAAAB6g/ztVWvRDHTMU/250caracteres.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 533px; height: 261px;" src="https://lh5.googleusercontent.com/-4aDaWO7mqxQ/ThIsW9m7ycI/AAAAAAAAB6g/ztVWvRDHTMU/250caracteres.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4267779693891515557?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4267779693891515557/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4267779693891515557' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4267779693891515557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4267779693891515557'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2011/07/250-caracteres.html' title='250 caracteres'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh5.googleusercontent.com/-4aDaWO7mqxQ/ThIsW9m7ycI/AAAAAAAAB6g/ztVWvRDHTMU/s72-c/250caracteres.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-2478199089125707181</id><published>2011-03-09T15:31:00.001-03:00</published><updated>2011-03-09T15:31:56.522-03:00</updated><title type='text'>Las Interrupciones en los Procesadores 80x86</title><content type='html'>&lt;h1 class="western" id="z5bq0"&gt;&lt;font size="4"&gt;1. Origen de las interrupciones.&lt;/font&gt;&lt;/h1&gt;&lt;p align="justify" class="western" id="z5bq17"&gt;&lt;br id="z5bq18"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq19"&gt; En las computadoras con procesadores 80x86 las interrupciones pueden ser originadas por la CPU (las excepciones), &amp;ldquo;disparando&amp;rdquo; el pin INTR (interrupciones enmascarables) o el NMI (interrupciones no enmascarables), o por las instrucciones INT 3, INT n, INTO o BOUND (interrupciones por software). &lt;/p&gt;&lt;h2 class="western" id="z5bq20"&gt; 1.1. Excepciones. &lt;/h2&gt;&lt;p align="justify" class="western" id="z5bq21"&gt;&lt;br id="z5bq22"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq23"&gt; Como ya se ha dicho, se nombra de esta manera a las interrupciones originadas por la CPU. INTEL las clasifica, seg&amp;uacute;n la direcci&amp;oacute;n de retorno de la rutina o proceso que atiende la interrupci&amp;oacute;n, de la siguiente manera: &lt;/p&gt;&lt;ul id="z5bq24"&gt;&lt;li id="z5bq25"&gt;&lt;p align="justify" class="western" id="z5bq26"&gt; Faults: la direcci&amp;oacute;n de retorno es la de la instrucci&amp;oacute;n que se ejecutaba cuando se origin&amp;oacute; la excepci&amp;oacute;n. Esta excepci&amp;oacute;n permite solucionar el problema y volver a ejecutar dicha instrucci&amp;oacute;n. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq27"&gt;&lt;p align="justify" class="western" id="z5bq28"&gt; Traps: la direcci&amp;oacute;n de retorno es la de la instrucci&amp;oacute;n que le sigue a la que se ejecutaba cuando se origin&amp;oacute; la excepci&amp;oacute;n. Son usadas exclusivamente para prop&amp;oacute;sito de depuraci&amp;oacute;n, como por ejemplo colocar un &amp;ldquo;breakpoint&amp;rdquo;. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq29"&gt;&lt;p align="justify" class="western" id="z5bq30"&gt; Aborts: a veces no es posible determinar la direcci&amp;oacute;n de retorno, por lo tanto tampoco es posible continuar con el programa luego de una excepci&amp;oacute;n de esta clase. Son causadas por fallas graves, como errores en el hardware o entradas err&amp;oacute;neas en las tablas del sistema. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p align="justify" class="western" id="z5bq31"&gt; Algunas excepciones generan un &amp;ldquo;error code&amp;rdquo; que proporcionan informaci&amp;oacute;n sobre estas. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq32"&gt;&lt;br id="z5bq33"&gt;&lt;/p&gt;&lt;table border="1" bordercolor="#000000" cellpadding="5" cellspacing="0" id="z5bq34" rules="cols" width="606"&gt;    &lt;tbody id="z5bq40"&gt;&lt;tr id="z5bq41" valign="top"&gt;&lt;td id="z5bq42" width="89"&gt;&lt;h3 align="center" class="western" id="z5bq43"&gt;&lt;font face="Times New Roman, serif" id="z5bq44"&gt;&lt;font id="z5bq45" size="3"&gt;Vector&lt;/font&gt;&lt;/font&gt;&lt;/h3&gt;&lt;/td&gt;&lt;td id="z5bq46" width="90"&gt;&lt;p align="center" class="western" id="z5bq47"&gt;&lt;b&gt;Mnemonico&lt;/b&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq49" width="198"&gt;&lt;p align="center" class="western" id="z5bq50"&gt;&lt;b&gt;Decripci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq52" width="88"&gt;&lt;p align="center" class="western" id="z5bq53"&gt;&lt;b&gt;Tipo&lt;/b&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq55" width="88"&gt;&lt;p align="center" class="western" id="z5bq56"&gt;&lt;b&gt;Error code&lt;/b&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;tbody id="z5bq58"&gt;&lt;tr id="z5bq59" valign="top"&gt;&lt;td id="z5bq60" width="89"&gt;&lt;p align="center" class="western" id="z5bq61"&gt; 0 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq62" width="90"&gt;&lt;p align="center" class="western" id="z5bq63"&gt; #DE &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq64" width="198"&gt;&lt;p align="center" class="western" id="z5bq65"&gt; Divide error &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq66" width="88"&gt;&lt;p align="center" class="western" id="z5bq67"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq68" width="88"&gt;&lt;p align="center" class="western" id="z5bq69"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq70" valign="top"&gt;&lt;td id="z5bq71" width="89"&gt;&lt;p align="center" class="western" id="z5bq72"&gt; 1 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq73" width="90"&gt;&lt;p align="center" class="western" id="z5bq74"&gt; #DB &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq75" width="198"&gt;&lt;p align="center" class="western" id="z5bq76"&gt; Debug &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq77" width="88"&gt;&lt;p align="center" class="western" id="z5bq78"&gt; Fault/Trap &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq79" width="88"&gt;&lt;p align="center" class="western" id="z5bq80"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq81" valign="top"&gt;&lt;td id="z5bq82" width="89"&gt;&lt;p align="center" class="western" id="z5bq83"&gt; 2 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq84" width="90"&gt;&lt;p align="center" class="western" id="z5bq85"&gt; - &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq86" width="198"&gt;&lt;p align="center" class="western" id="z5bq87"&gt; NMI interrupt &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq88" width="88"&gt;&lt;p align="center" class="western" id="z5bq89"&gt; Interrupci&amp;oacute;n &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq90" width="88"&gt;&lt;p align="center" class="western" id="z5bq91"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq92" valign="top"&gt;&lt;td id="z5bq93" width="89"&gt;&lt;p align="center" class="western" id="z5bq94"&gt; 3 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq95" width="90"&gt;&lt;p align="center" class="western" id="z5bq96"&gt; #BP &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq97" width="198"&gt;&lt;p align="center" class="western" id="z5bq98"&gt; Breakpoint &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq99" width="88"&gt;&lt;p align="center" class="western" id="z5bq100"&gt; Trap &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq101" width="88"&gt;&lt;p align="center" class="western" id="z5bq102"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq103" valign="top"&gt;&lt;td id="z5bq104" width="89"&gt;&lt;p align="center" class="western" id="z5bq105"&gt; 4 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq106" width="90"&gt;&lt;p align="center" class="western" id="z5bq107"&gt; #OF &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq108" width="198"&gt;&lt;p align="center" class="western" id="z5bq109"&gt; Overflow &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq110" width="88"&gt;&lt;p align="center" class="western" id="z5bq111"&gt; Trap &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq112" width="88"&gt;&lt;p align="center" class="western" id="z5bq113"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq114" valign="top"&gt;&lt;td id="z5bq115" width="89"&gt;&lt;p align="center" class="western" id="z5bq116"&gt; 5 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq117" width="90"&gt;&lt;p align="center" class="western" id="z5bq118"&gt; #BR &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq119" width="198"&gt;&lt;p align="center" class="western" id="z5bq120"&gt; Range exceeded &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq121" width="88"&gt;&lt;p align="center" class="western" id="z5bq122"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq123" width="88"&gt;&lt;p align="center" class="western" id="z5bq124"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq125" valign="top"&gt;&lt;td id="z5bq126" width="89"&gt;&lt;p align="center" class="western" id="z5bq127"&gt; 6 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq128" width="90"&gt;&lt;p align="center" class="western" id="z5bq129"&gt; #UD &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq130" width="198"&gt;&lt;p align="center" class="western" id="z5bq131"&gt; Invalid opcode &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq132" width="88"&gt;&lt;p align="center" class="western" id="z5bq133"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq134" width="88"&gt;&lt;p align="center" class="western" id="z5bq135"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq136" valign="top"&gt;&lt;td id="z5bq137" width="89"&gt;&lt;p align="center" class="western" id="z5bq138"&gt; 7 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq139" width="90"&gt;&lt;p align="center" class="western" id="z5bq140"&gt; #NM &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq141" width="198"&gt;&lt;p align="center" class="western" id="z5bq142"&gt; No math coprocessor &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq143" width="88"&gt;&lt;p align="center" class="western" id="z5bq144"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq145" width="88"&gt;&lt;p align="center" class="western" id="z5bq146"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq147" valign="top"&gt;&lt;td id="z5bq148" width="89"&gt;&lt;p align="center" class="western" id="z5bq149"&gt; 8 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq150" width="90"&gt;&lt;p align="center" class="western" id="z5bq151"&gt; #DF &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq152" width="198"&gt;&lt;p align="center" class="western" id="z5bq153"&gt; Doble fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq154" width="88"&gt;&lt;p align="center" class="western" id="z5bq155"&gt; Abort &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq156" width="88"&gt;&lt;p align="center" class="western" id="z5bq157"&gt; Si &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq158" valign="top"&gt;&lt;td id="z5bq159" width="89"&gt;&lt;p align="center" class="western" id="z5bq160"&gt; 9 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq161" width="90"&gt;&lt;p align="center" class="western" id="z5bq162"&gt; - &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq163" width="198"&gt;&lt;p align="center" class="western" id="z5bq164"&gt; Coprocesor segment overrun &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq165" width="88"&gt;&lt;p align="center" class="western" id="z5bq166"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq167" width="88"&gt;&lt;p align="center" class="western" id="z5bq168"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq169" valign="top"&gt;&lt;td id="z5bq170" width="89"&gt;&lt;p align="center" class="western" id="z5bq171"&gt; 10 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq172" width="90"&gt;&lt;p align="center" class="western" id="z5bq173"&gt; #TS &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq174" width="198"&gt;&lt;p align="center" class="western" id="z5bq175"&gt; Invalid TSS &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq176" width="88"&gt;&lt;p align="center" class="western" id="z5bq177"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq178" width="88"&gt;&lt;p align="center" class="western" id="z5bq179"&gt; Si &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq180" valign="top"&gt;&lt;td id="z5bq181" width="89"&gt;&lt;p align="center" class="western" id="z5bq182"&gt; 11 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq183" width="90"&gt;&lt;p align="center" class="western" id="z5bq184"&gt; #NP &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq185" width="198"&gt;&lt;p align="center" class="western" id="z5bq186"&gt; Segment not present &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq187" width="88"&gt;&lt;p align="center" class="western" id="z5bq188"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq189" width="88"&gt;&lt;p align="center" class="western" id="z5bq190"&gt; Si &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq191" valign="top"&gt;&lt;td id="z5bq192" width="89"&gt;&lt;p align="center" class="western" id="z5bq193"&gt; 12 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq194" width="90"&gt;&lt;p align="center" class="western" id="z5bq195"&gt; #SS &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq196" width="198"&gt;&lt;p align="center" class="western" id="z5bq197"&gt; Stack-segment fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq198" width="88"&gt;&lt;p align="center" class="western" id="z5bq199"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq200" width="88"&gt;&lt;p align="center" class="western" id="z5bq201"&gt; Si &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq202" valign="top"&gt;&lt;td id="z5bq203" width="89"&gt;&lt;p align="center" class="western" id="z5bq204"&gt; 13 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq205" width="90"&gt;&lt;p align="center" class="western" id="z5bq206"&gt; #GP &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq207" width="198"&gt;&lt;p align="center" class="western" id="z5bq208"&gt; General protection &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq209" width="88"&gt;&lt;p align="center" class="western" id="z5bq210"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq211" width="88"&gt;&lt;p align="center" class="western" id="z5bq212"&gt; Si &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq213" valign="top"&gt;&lt;td id="z5bq214" width="89"&gt;&lt;p align="center" class="western" id="z5bq215"&gt; 14 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq216" width="90"&gt;&lt;p align="center" class="western" id="z5bq217"&gt; #PF &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq218" width="198"&gt;&lt;p align="center" class="western" id="z5bq219"&gt; Page fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq220" width="88"&gt;&lt;p align="center" class="western" id="z5bq221"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq222" width="88"&gt;&lt;p align="center" class="western" id="z5bq223"&gt; Si &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq224" valign="top"&gt;&lt;td id="z5bq225" width="89"&gt;&lt;p align="center" class="western" id="z5bq226"&gt; 15 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq227" width="90"&gt;&lt;p align="center" class="western" id="z5bq228"&gt; - &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq229" width="198"&gt;&lt;p align="center" class="western" id="z5bq230"&gt; (Intel reserved) &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq231" width="88"&gt;&lt;p align="center" class="western" id="z5bq232"&gt; - &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq233" width="88"&gt;&lt;p align="center" class="western" id="z5bq234"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq235" valign="top"&gt;&lt;td id="z5bq236" width="89"&gt;&lt;p align="center" class="western" id="z5bq237"&gt; 16 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq238" width="90"&gt;&lt;p align="center" class="western" id="z5bq239"&gt; #MF &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq240" width="198"&gt;&lt;p align="center" class="western" id="z5bq241"&gt; Math fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq242" width="88"&gt;&lt;p align="center" class="western" id="z5bq243"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq244" width="88"&gt;&lt;p align="center" class="western" id="z5bq245"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq246" valign="top"&gt;&lt;td id="z5bq247" width="89"&gt;&lt;p align="center" class="western" id="z5bq248"&gt; 17 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq249" width="90"&gt;&lt;p align="center" class="western" id="z5bq250"&gt; #AC &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq251" width="198"&gt;&lt;p align="center" class="western" id="z5bq252"&gt; Alignment check &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq253" width="88"&gt;&lt;p align="center" class="western" id="z5bq254"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq255" width="88"&gt;&lt;p align="center" class="western" id="z5bq256"&gt; Si &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq257" valign="top"&gt;&lt;td id="z5bq258" width="89"&gt;&lt;p align="center" class="western" id="z5bq259"&gt; 18 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq260" width="90"&gt;&lt;p align="center" class="western" id="z5bq261"&gt; #MC &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq262" width="198"&gt;&lt;p align="center" class="western" id="z5bq263"&gt; Machine check &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq264" width="88"&gt;&lt;p align="center" class="western" id="z5bq265"&gt; Abort &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq266" width="88"&gt;&lt;p align="center" class="western" id="z5bq267"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq268" valign="top"&gt;&lt;td id="z5bq269" width="89"&gt;&lt;p align="center" class="western" id="z5bq270"&gt; 19 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq271" width="90"&gt;&lt;p align="center" class="western" id="z5bq272"&gt; #XF &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq273" width="198"&gt;&lt;p align="center" class="western" id="z5bq274"&gt; Streaming SIMD extensions &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq275" width="88"&gt;&lt;p align="center" class="western" id="z5bq276"&gt; Fault &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq277" width="88"&gt;&lt;p align="center" class="western" id="z5bq278"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq279" valign="top"&gt;&lt;td id="z5bq280" width="89"&gt;&lt;p align="center" class="western" id="z5bq281"&gt; 20-31 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq282" width="90"&gt;&lt;p align="center" class="western" id="z5bq283"&gt; - &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq284" width="198"&gt;&lt;p align="center" class="western" id="z5bq285"&gt; (Intel reserved) &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq286" width="88"&gt;&lt;p align="center" class="western" id="z5bq287"&gt; - &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq288" width="88"&gt;&lt;p align="center" class="western" id="z5bq289"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq290" valign="top"&gt;&lt;td id="z5bq291" width="89"&gt;&lt;p align="center" class="western" id="z5bq292"&gt; 32-255 &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq293" width="90"&gt;&lt;p align="center" class="western" id="z5bq294"&gt; - &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq295" width="198"&gt;&lt;p align="center" class="western" id="z5bq296"&gt; User defined &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq297" width="88"&gt;&lt;p align="center" class="western" id="z5bq298"&gt; Interrupci&amp;oacute;n &lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq299" width="88"&gt;&lt;p align="center" class="western" id="z5bq300"&gt; No &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 class="western" id="z5bq301"&gt; 1.2. Interrupciones externas. &lt;/h2&gt;&lt;p align="justify" class="western" id="z5bq302"&gt;&lt;br id="z5bq303"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq304"&gt; En las PCs de IBM la CPU tiene conectado un controlador de interrupciones programable 8259 al pin INTR. Los distintos dispositivos se conectan a este chip (por las IRQ) y le solicitan que interrumpa al procesador cuando lo requieran. Este chip no solo debe interrumpir al procesador, sino que tambi&amp;eacute;n debe indicarle cu&amp;aacute;l es el vector asociado al dispositivo (se hablar&amp;aacute; de los vectores luego) que solicit&amp;oacute; la interrupci&amp;oacute;n. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq305"&gt; A partir de las ATs las PCs comenzaron a venir con dos 8259 conectados en cascada, permitiendo conectar hasta 15 dispositivos. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq306"&gt; Estas interrupciones se pueden enmascarar indiscriminadamente desde el procesador, poniendo el flag IF en 0, o selectivamente desde el 8259. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq307"&gt; Otra forma de generar interrupciones desde el exterior de la CPU es disparando por el pin NMI, esto ocurre cuando hay una falla de hardware, por ejemplo problemas con la memoria. En este caso el vector es 2 y no es posible enmascarar estas interrupciones. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq308"&gt;&lt;br id="z5bq309"&gt;&lt;/p&gt;&lt;h2 class="western" id="z5bq310"&gt; 1.3. Interrupciones por software. &lt;/h2&gt;&lt;p align="justify" class="western" id="z5bq311"&gt;&lt;br id="z5bq312"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq313"&gt; Es posible generar interrupciones con el vector deseado mediante la instrucci&amp;oacute;n INT n. Esto es &amp;uacute;til para implementar &amp;ldquo;breakpoints&amp;rdquo; y &amp;ldquo;system calls&amp;rdquo;. Las system calls son un conjunto de rutinas y procesos que ofrece el sistema operativo a los programadores de aplicaciones para que tengan acceso restringido a los recursos del sistema. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq314"&gt; Linux implementa las &amp;ldquo;system calls&amp;rdquo; en el vector 0x80, por lo tanto para invocarlas hay que hacerlo con la instrucci&amp;oacute;n INT 0x80. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq315"&gt;&lt;font face="Arial, sans-serif" id="z5bq316"&gt;&lt;font id="z5bq317" size="4"&gt;&lt;b&gt;Anexo 1.A. El controlador de interrupciones 8259.&lt;/b&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq319"&gt;&lt;br id="z5bq320"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq321"&gt;&lt;b&gt;1.A.1 La interface de interrupci&amp;oacute;n con el 80x86.&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq323"&gt;&lt;br id="z5bq324"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq325"&gt; Los procesadores 80x86 poseen s&amp;oacute;lo una l&amp;iacute;nea de entrada sobre la cual pueden recibir una se&amp;ntilde;al de interrupci&amp;oacute;n. El 8259 PIC &amp;ndash; Programmable Interrupt Controller (Controlador de Interrupciones Programable) administra las m&amp;uacute;ltiples interrupciones de los m&amp;uacute;ltiples dispositivos, para entregarle las solicitudes al procesador 80x86 de a una. Para esto se lo coloca entre el microprocesador 80x86 y los dispositivos. &lt;/p&gt;&lt;p align="center" class="western" id="z5bq326"&gt;&lt;img align="bottom" border="0" height="200" id="z5bq327" name="graphics1" src="http://docs.google.com/File?id=dc94ptfk_18hf86jqjs" width="342"&gt;&lt;/p&gt;&lt;table border="1" bordercolor="#000000" cellpadding="5" cellspacing="0" id="z5bq328" width="601"&gt;&lt;tbody id="z5bq330"&gt;&lt;tr id="z5bq331"&gt;&lt;td id="z5bq332" valign="top" width="589"&gt;&lt;p align="center" class="western" id="z5bq333"&gt;&lt;font id="z5bq334" size="2"&gt;Conexi&amp;oacute;n entre los dispositivos y el 80x86 a trav&amp;eacute;s del 8259 PIC&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p align="center" class="western" id="z5bq335"&gt;&lt;br id="z5bq336"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq337"&gt;&lt;b&gt;1.A.2 El 8259 PIC (Programmable Interrupt Controller) &lt;/b&gt;&lt;/p&gt;&lt;p align="center" class="western" id="z5bq339"&gt;&lt;br id="z5bq340"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq341"&gt; El 8259 PIC controla las interrupciones por hardware, permite acoplarse con otros 8259 en cascada soportando hasta 64 niveles de interrupci&amp;oacute;n. La mayor&amp;iacute;a de las PC s&amp;oacute;lo tienen 2 de estos alojados en alguna direcci&amp;oacute;n. Uno maneja los IRQ del 0 al 7 y el otro del 8 al 15, dando en total 15 l&amp;iacute;neas individuales de IRQ. &lt;/p&gt;&lt;p align="justify" id="z5bq342"&gt; El PIC nos permite enmascarar IRQs individuales, esto significa que esas solicitudes no podr&amp;aacute;n llegar al procesador. C&amp;oacute;mo hay 2 PICs alojados en diferentes direcciones, debemos determinar cual PIC necesitamos usar. El primer PIC, localizado en la direcci&amp;oacute;n base 0x20h controla los IRQ 0 a IRQ 7. El segundo PIC est&amp;aacute; localizado en la direcci&amp;oacute;n base 0xA0h, y controla las IRQs del 8 al 15. El formato de bits de la Operation Control Word 1 (OCW1 es la instrucci&amp;oacute;n para enmascarar o desenmascarar las solicitudes) es el siguiente: &lt;/p&gt;&lt;center id="z5bq343"&gt;&lt;table border="1" bordercolor="#c0c0c0" cellpadding="1" cellspacing="3" id="z5bq344" width="582"&gt;     &lt;tbody id="z5bq351"&gt;&lt;tr id="z5bq352"&gt;&lt;td colspan="3" id="z5bq353" width="286"&gt;&lt;p align="center" class="western" id="z5bq354"&gt;&lt;font id="z5bq355" size="2"&gt;&lt;b&gt;PIC maestro&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td colspan="3" id="z5bq357" width="280"&gt;&lt;p align="center" class="western" id="z5bq358"&gt;&lt;font id="z5bq359" size="2"&gt;&lt;b&gt;PIC esclavo&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq361"&gt;&lt;td id="z5bq362" width="23"&gt;&lt;p align="center" class="western" id="z5bq363"&gt;&lt;font id="z5bq364" size="2"&gt;&lt;b&gt;Bit&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq366" width="78"&gt;&lt;p align="center" class="western" id="z5bq367"&gt;&lt;font id="z5bq368" size="2"&gt;&lt;b&gt;Disable IRQ&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq370" width="175"&gt;&lt;p align="center" class="western" id="z5bq371"&gt;&lt;font id="z5bq372" size="2"&gt;&lt;b&gt;Funci&amp;oacute;n&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq374" width="31"&gt;&lt;p align="center" class="western" id="z5bq375"&gt;&lt;font id="z5bq376" size="2"&gt;&lt;b&gt;Bit&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq378" width="83"&gt;&lt;p align="center" class="western" id="z5bq379"&gt;&lt;font id="z5bq380" size="2"&gt;&lt;b&gt;Disable IRQ&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq382" width="156"&gt;&lt;p align="center" class="western" id="z5bq383"&gt;&lt;font id="z5bq384" size="2"&gt;&lt;b&gt;Funci&amp;oacute;n&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq386"&gt;&lt;td id="z5bq387" width="23"&gt;&lt;p align="center" class="western" id="z5bq388"&gt;&lt;font id="z5bq389" size="2"&gt;7&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq390" width="78"&gt;&lt;p align="center" class="western" id="z5bq391"&gt;&lt;font id="z5bq392" size="2"&gt;IRQ7&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq393" width="175"&gt;&lt;p class="western" id="z5bq394"&gt;&lt;font id="z5bq395" size="2"&gt;Puerto Paralelo&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq396" width="31"&gt;&lt;p align="center" class="western" id="z5bq397"&gt;&lt;font id="z5bq398" size="2"&gt;7&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq399" width="83"&gt;&lt;p align="center" class="western" id="z5bq400"&gt;&lt;font id="z5bq401" size="2"&gt;IRQ15&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq402" width="156"&gt;&lt;p class="western" id="z5bq403"&gt;&lt;font id="z5bq404" size="2"&gt;Reservado.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq406"&gt;&lt;td id="z5bq407" width="23"&gt;&lt;p align="center" class="western" id="z5bq408"&gt;&lt;font id="z5bq409" size="2"&gt;6&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq410" width="78"&gt;&lt;p align="center" class="western" id="z5bq411"&gt;&lt;font id="z5bq412" size="2"&gt;IRQ6&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq413" width="175"&gt;&lt;p class="western" id="z5bq414"&gt;&lt;font id="z5bq415" size="2"&gt;Disco Flexible&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq416" width="31"&gt;&lt;p align="center" class="western" id="z5bq417"&gt;&lt;font id="z5bq418" size="2"&gt;6&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq419" width="83"&gt;&lt;p align="center" class="western" id="z5bq420"&gt;&lt;font id="z5bq421" size="2"&gt;IRQ14&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq422" width="156"&gt;&lt;p class="western" id="z5bq423"&gt;&lt;font id="z5bq424" size="2"&gt;Disco R&amp;iacute;gido.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq425"&gt;&lt;td id="z5bq426" width="23"&gt;&lt;p align="center" class="western" id="z5bq427"&gt;&lt;font id="z5bq428" size="2"&gt;5&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq429" width="78"&gt;&lt;p align="center" class="western" id="z5bq430"&gt;&lt;font id="z5bq431" size="2"&gt;IRQ5&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq432" width="175"&gt;&lt;p class="western" id="z5bq433"&gt;&lt;font id="z5bq434" size="2"&gt;Reservado/Tarjeta de sonido&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq435" width="31"&gt;&lt;p align="center" class="western" id="z5bq436"&gt;&lt;font id="z5bq437" size="2"&gt;5&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq438" width="83"&gt;&lt;p align="center" class="western" id="z5bq439"&gt;&lt;font id="z5bq440" size="2"&gt;IRQ13&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq441" width="156"&gt;&lt;p class="western" id="z5bq442"&gt;&lt;font id="z5bq443" size="2"&gt;Coprocesador matem&amp;aacute;tico.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq444"&gt;&lt;td id="z5bq445" width="23"&gt;&lt;p align="center" class="western" id="z5bq446"&gt;&lt;font id="z5bq447" size="2"&gt;4&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq448" width="78"&gt;&lt;p align="center" class="western" id="z5bq449"&gt;&lt;font id="z5bq450" size="2"&gt;IRQ4&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq451" width="175"&gt;&lt;p class="western" id="z5bq452"&gt;&lt;font id="z5bq453" size="2"&gt;Puerto serie &lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq454" width="31"&gt;&lt;p align="center" class="western" id="z5bq455"&gt;&lt;font id="z5bq456" size="2"&gt;4&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq457" width="83"&gt;&lt;p align="center" class="western" id="z5bq458"&gt;&lt;font id="z5bq459" size="2"&gt;IRQ12&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq460" width="156"&gt;&lt;p class="western" id="z5bq461"&gt;&lt;font id="z5bq462" size="2"&gt;PS/2 Mouse&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq463"&gt;&lt;td id="z5bq464" width="23"&gt;&lt;p align="center" class="western" id="z5bq465"&gt;&lt;font id="z5bq466" size="2"&gt;3&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq467" width="78"&gt;&lt;p align="center" class="western" id="z5bq468"&gt;&lt;font id="z5bq469" size="2"&gt;IRQ3&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq470" width="175"&gt;&lt;p class="western" id="z5bq471"&gt;&lt;font id="z5bq472" size="2"&gt;Puerto serie&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq473" width="31"&gt;&lt;p align="center" class="western" id="z5bq474"&gt;&lt;font id="z5bq475" size="2"&gt;3&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq476" width="83"&gt;&lt;p align="center" class="western" id="z5bq477"&gt;&lt;font id="z5bq478" size="2"&gt;IRQ11&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq479" width="156"&gt;&lt;p class="western" id="z5bq480"&gt;&lt;font id="z5bq481" size="2"&gt;Reservado.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq482"&gt;&lt;td id="z5bq483" width="23"&gt;&lt;p align="center" class="western" id="z5bq484"&gt;&lt;font id="z5bq485" size="2"&gt;2&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq486" width="78"&gt;&lt;p align="center" class="western" id="z5bq487"&gt;&lt;font id="z5bq488" size="2"&gt;IRQ2&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq489" width="175"&gt;&lt;p class="western" id="z5bq490"&gt;&lt;font id="z5bq491" size="2"&gt;PIC2&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq492" width="31"&gt;&lt;p align="center" class="western" id="z5bq493"&gt;&lt;font id="z5bq494" size="2"&gt;2&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq495" width="83"&gt;&lt;p align="center" class="western" id="z5bq496"&gt;&lt;font id="z5bq497" size="2"&gt;IRQ10&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq498" width="156"&gt;&lt;p class="western" id="z5bq499"&gt;&lt;font id="z5bq500" size="2"&gt;Reservado.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq501"&gt;&lt;td id="z5bq502" width="23"&gt;&lt;p align="center" class="western" id="z5bq503"&gt;&lt;font id="z5bq504" size="2"&gt;1&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq505" width="78"&gt;&lt;p align="center" class="western" id="z5bq506"&gt;&lt;font id="z5bq507" size="2"&gt;IRQ1&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq508" width="175"&gt;&lt;p class="western" id="z5bq509"&gt;&lt;font id="z5bq510" size="2"&gt;Teclado&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq511" width="31"&gt;&lt;p align="center" class="western" id="z5bq512"&gt;&lt;font id="z5bq513" size="2"&gt;1&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq514" width="83"&gt;&lt;p align="center" class="western" id="z5bq515"&gt;&lt;font id="z5bq516" size="2"&gt;IRQ9&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq517" width="156"&gt;&lt;p class="western" id="z5bq518"&gt;&lt;font id="z5bq519" size="2"&gt;Redirecci&amp;oacute;n del IRQ2&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq520"&gt;&lt;td id="z5bq521" width="23"&gt;&lt;p align="center" class="western" id="z5bq522"&gt;&lt;font id="z5bq523" size="2"&gt;0&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq524" width="78"&gt;&lt;p align="center" class="western" id="z5bq525"&gt;&lt;font id="z5bq526" size="2"&gt;IRQ0&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq527" width="175"&gt;&lt;p class="western" id="z5bq528"&gt;&lt;font id="z5bq529" size="2"&gt;Timer del sistema&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq530" width="31"&gt;&lt;p align="center" class="western" id="z5bq531"&gt;&lt;font id="z5bq532" size="2"&gt;0&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq533" width="83"&gt;&lt;p align="center" class="western" id="z5bq534"&gt;&lt;font id="z5bq535" size="2"&gt;IRQ8&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;td id="z5bq536" width="156"&gt;&lt;p class="western" id="z5bq537"&gt;&lt;font id="z5bq538" size="2"&gt;Reloj en tiempo real.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq539"&gt;&lt;td colspan="6" id="z5bq540" width="572"&gt;&lt;p align="center" class="western" id="z5bq541"&gt;&lt;font id="z5bq542" size="2"&gt;Asignaciones t&amp;iacute;picas de IRQ y su correspondiente bit para enmascarar o desenmascarar las solicitudes.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;&lt;p id="z5bq543"&gt; Como se ve en la tabla y en la siguiente figura, el IRQ2 est&amp;aacute; conectado al PIC 2, as&amp;iacute;, si se enmascara este IRQ, se deshabilitar&amp;aacute;n las IRQ 8 a la 15. &lt;/p&gt;&lt;table border="1" bordercolor="#000000" cellpadding="5" cellspacing="0" id="z5bq544" width="601"&gt;&lt;tbody id="z5bq546"&gt;&lt;tr id="z5bq547"&gt;&lt;td id="z5bq548" valign="top" width="589"&gt;&lt;p align="center" id="z5bq549"&gt;&lt;img align="bottom" border="0" height="314" id="z5bq550" name="graphics2" src="http://docs.google.com/File?id=dc94ptfk_19fv49zndp" width="293"&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq551"&gt;&lt;td id="z5bq552" valign="top" width="589"&gt;&lt;p align="center" id="z5bq553"&gt;&lt;font id="z5bq554" size="2"&gt;Conexi&amp;oacute;n en cascada entre 2 PICs&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p align="center" id="z5bq555"&gt;&lt;br id="z5bq556"&gt;&lt;/p&gt;&lt;p id="z5bq557"&gt;&lt;br id="z5bq558"&gt;&lt;/p&gt;&lt;p id="z5bq559"&gt;&lt;b&gt;&lt;font id="z5bq564" size="3"&gt;&lt;font face="Times New Roman, serif" id="z5bq565"&gt;1.A.3 Las Operaciones del PIC&lt;/font&gt;&lt;/font&gt;&lt;/b&gt;&lt;/p&gt;&lt;p id="z5bq566"&gt;&lt;br id="z5bq567"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq568"&gt; La programaci&amp;oacute;n del 8259 consiste de dos acciones b&amp;aacute;sicas: &lt;/p&gt;&lt;ul id="z5bq569"&gt;&lt;li id="z5bq570"&gt;&lt;p align="justify" class="western" id="z5bq571"&gt; Primero habilitamos o deshabilitamos cada fuente de interrupci&amp;oacute;n independientemente escribiendo un valor en el registro de m&amp;aacute;scara de interrupci&amp;oacute;n (IMR). El IMR es un registro del 8259 ubicado en el puerto 21h para el PIC maestro y ubicado en A1h para el PIC esclavo. Cada bit del IMR corresponde a una fuente, si el bit es 0, entonces su correspondiente interrupci&amp;oacute;n esta habilitada. Si el bit del IMR es 1, entonces la fuente de interrupci&amp;oacute;n se deshabilitada (se enmascara) y no puede generar interrupci&amp;oacute;n. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p align="justify" class="western" id="z5bq572"&gt; La definici&amp;oacute;n para cada uno de los bits del IMR es la siguiente: el bit 0 corresponde a la IRQ0, el bit 1 a la IRQ1 y as&amp;iacute; sucesivamente con todos los bits. Por ejemplo, si queremos deshabilitar las interrupciones de todos los dispositivos excepto el teclado. Esto pudiera lograrse con las siguientes instrucciones: &lt;/p&gt;&lt;p class="western" id="z5bq573"&gt;&lt;font face="Courier, monospace" id="z5bq574"&gt;mov al, 0FDh&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq575"&gt;&lt;font face="Courier, monospace" id="z5bq576"&gt;out 21h, al&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq577"&gt; O en el lenguaje C, pero manteniendo los valores anteriores del puerto 21h: &lt;/p&gt;&lt;p id="z5bq578"&gt;&lt;font id="z5bq582" size="3"&gt;&lt;font face="Courier, monospace" id="z5bq583"&gt;outportb(0x21,(inportb(0x21) &amp;amp; 0xFD);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;ul id="z5bq584"&gt;&lt;li id="z5bq585"&gt;&lt;p align="justify" class="western" id="z5bq586"&gt; La segunda acci&amp;oacute;n programando el 8259 tiene que ver con indicarle el final de la rutina de servicio a interrupci&amp;oacute;n. Esto se logra enviando al registro de comando del 8259, el comando de fin de interrupci&amp;oacute;n (EOI), representado por 20h. Coincidentemente, a este registro se accede v&amp;iacute;a el puerto 20h para el PIC maestro y v&amp;iacute;a A0h para el PIC esclavo, de tal manera que la se&amp;ntilde;al de fin interrupci&amp;oacute;n se env&amp;iacute;a mandando el comando EOI, como se ejemplifica en las siguientes instrucciones: &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="western" id="z5bq587"&gt;&lt;font face="Courier, monospace" id="z5bq588"&gt;mov al, 20h&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq589"&gt;&lt;font face="Courier, monospace" id="z5bq590"&gt;mov 20h, al&lt;/font&gt;&lt;/p&gt;&lt;p id="z5bq591"&gt;&lt;br id="z5bq592"&gt;&lt;/p&gt;&lt;table border="1" bordercolor="#000000" cellpadding="5" cellspacing="0" id="z5bq593" width="601"&gt;&lt;tbody id="z5bq595"&gt;&lt;tr id="z5bq596"&gt;&lt;td id="z5bq597" valign="top" width="589"&gt;&lt;p align="center" class="western" id="z5bq598"&gt;&lt;img align="bottom" border="0" height="233" id="z5bq599" name="graphics3" src="http://docs.google.com/File?id=dc94ptfk_20hbk753c2" width="464"&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq600"&gt;&lt;td id="z5bq601" valign="top" width="589"&gt;&lt;p align="center" class="western" id="z5bq602"&gt;&lt;font id="z5bq603" size="2"&gt;Diagrama de Bloques del 8259 PIC&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p align="justify" class="western" id="z5bq604" style="margin-left:1.25in"&gt;&lt;br id="z5bq605"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq606"&gt; Como se puede ver en la figura anterior, las 8 l&amp;iacute;neas individuales de Interrupt Request, primero pasan por el Interrupt Mask Register (IMR), para ver si han sido enmascaradas o no. Si est&amp;aacute;n enmascaradas, entonces no ser&amp;aacute;n procesadas hasta nuevo aviso. Por otro lado, si no est&amp;aacute;n enmascaradas, estas registrar&amp;aacute;n sus solicitudes en el Interrupt Request Register (IRR). &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq607"&gt; El IRR mantendr&amp;aacute; todas las solicitudes IRQs hasta que hayan sido tratadas apropiadamente. Si es necesario, este registro podr&amp;aacute; ser le&amp;iacute;do colocando correctamente bits en la &lt;b&gt;Operation Control World 3. &lt;/b&gt;El Priority Resolver, simplemente selecciona el IRQ con mayor prioridad. Aunque la m&amp;aacute;s alta prioridad dentro de cada 8259 es la IRQ0 para el maestro e IRQ8 para el esclavo, la conexi&amp;oacute;n a trav&amp;eacute;s de IRQ2 causa que IRQ8-IRQ15 sean las siguientes peticiones de prioridad m&amp;aacute;s alta despu&amp;eacute;s de IRQ1. As&amp;iacute;, el orden de prioridad por omisi&amp;oacute;n para las peticiones de interrupci&amp;oacute;n es IRQ0, IRQ1, IRQ8-IRQ15, IRQ3-IRQ7. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq609"&gt; Una vez que el PIC ha determinado cual IRQ procesar, se lo debe decir al procesador, as&amp;iacute; llamar&amp;aacute; a la ISR de forma autom&amp;aacute;tica. Este proceso es realizado enviando una se&amp;ntilde;al INT al procesador, es decir, es usada la l&amp;iacute;nea INT del procesador. El procesador entonces terminar&amp;aacute; el proceso de la instrucci&amp;oacute;n actual y reconocer&amp;aacute; la solicitud INT con un pulso INTA (Interrupt Acknowledge). &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq610"&gt; Luego de recibir la se&amp;ntilde;al INTA proveniente del procesador, la IRQ que el PIC est&amp;aacute; actualmente procesando es almacenada en el In-Service Register (ISR), el cual, como su nombre lo indica, muestra que IRQ est&amp;aacute; actualmente siendo servida. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq611"&gt; Otro pulso INTA ser&amp;aacute; enviado por el procesador, para decirle al PIC que coloque un puntero de 8 bits en el bus de datos, correspondiente al n&amp;uacute;mero de IRQ. Si una IRQ atendida por el PIC2 requiere el servicio, entonces el PIC2 enviar&amp;aacute; el puntero. El procesador maestro PIC1, seleccionar&amp;aacute; al PIC2 para que env&amp;iacute;e el puntero, colocando la identificaci&amp;oacute;n de esclavo (Slave ID) del PIC2 en la linea de la cascada, el cual tiene un ancho de tres cables (CAS0, CAS1, CAS2) entre los PICs. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq612"&gt; Los cinco (5) bits m&amp;aacute;s significantes del puntero es colocado usando el Initialization Command Word 2 (ICW2). Este ser&amp;aacute; 00001 para el PIC 1 y 01110 para el PIC2. Los 3 bits menos significantes ser&amp;aacute;n enviados para indicar el n&amp;uacute;mero de IRQ que pide atenci&amp;oacute;n. Por ejemplo, Si el IRQ solicita atenci&amp;oacute;n, entonces, el puntero de 8 bits estar&amp;aacute; formado por 00001 en los 5 bits m&amp;aacute;s significativos y 011 (IR3) para los bits menos significativos. Juntando esto quedar&amp;aacute; 00001011 o 0x0B, el cual es el vector de interrupciones del IRQ 3 (como se puede ver en la tabla de asignaciones t&amp;iacute;picas de IRQ mostrada anteriormente en este TP). &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq613"&gt; El mismo principio se aplica al PIC2. Si el IRQ 10 requiere un servicio, entonces ser&amp;aacute; enviado el byte 01110010, el cual representa la interrupci&amp;oacute;n 72h. Como la IRQ10 est&amp;aacute; en el PIC2, los 3 bits menos significativos usados ser&amp;aacute;n 010. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq614"&gt; Una vez que la ISR ha hecho todo lo necesario, enviar&amp;aacute; una End of Interrupt (EOI) hacia el PIC, el cual vuelve a poner en uso al In-Service Register. Si la solicitud proviene del PIC2, entonces, las se&amp;ntilde;ales EOIs se deber&amp;aacute;n enviar a ambos PICs. Luego el PIC determinar&amp;aacute; la pr&amp;oacute;xima interrupci&amp;oacute;n en prioridad y se repite el mismo proceso. Si no hay solicitudes de interrupci&amp;oacute;n presentes, el PIC esperar&amp;aacute; por la pr&amp;oacute;xima solicitud antes de interrumpir el procesador. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq615"&gt;&lt;br id="z5bq616"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq617"&gt;&lt;b&gt;1.A.4 Redireccionamiento de las IRQ2/IRQ9&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq619"&gt;&lt;br id="z5bq620"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq621"&gt; La IRQ 2 del PIC maestro se usa para conectar a otro PIC como esclavo, no permitiendo que otro dispositivo sea conectado a esta IRQ y la IRQ2 se desv&amp;iacute;a hacia la IRQ9 (en el segundo controlador). Un dispositivo de hardware usando la IRQ2, instalar&amp;iacute;a su ISR en INT 0x0A. Por lo tanto ser&amp;aacute; usada una rutina ISR en INT 71h, la cual enviar&amp;aacute; una EOI al PIC2 y luego llamar&amp;aacute; a la ISR en INT 0x0A. Parte del c&amp;oacute;digo en assembler de la ISR para la IRQ9 ser&amp;iacute;a como el siguiente: &lt;/p&gt;&lt;p id="z5bq623"&gt;&lt;font face="Courier, monospace" id="z5bq624"&gt;&lt;font id="z5bq625" size="3"&gt;MOV AL,20&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p id="z5bq626"&gt;&lt;font face="Courier, monospace" id="z5bq627"&gt;&lt;font id="z5bq628" size="3"&gt;OUT A0,AL ; env&amp;iacute;a EOI al PIC2&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p id="z5bq629"&gt;&lt;font face="Courier, monospace" id="z5bq630"&gt;&lt;font id="z5bq631" size="3"&gt;INT 0A ; llama a la ISR para la IRQ2&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p id="z5bq632"&gt;&lt;font face="Courier, monospace" id="z5bq633"&gt;&lt;font id="z5bq634" size="3"&gt;IRET&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq635"&gt;&lt;font face="Times New Roman, serif" id="z5bq636"&gt;&lt;font id="z5bq637" size="3"&gt; La rutina s&amp;oacute;lo env&amp;iacute;a una EOI al PIC2, como se espera que se ejecute una rutina ISR escrita para la IRQ2, esta se encargar&amp;aacute; de enviar una EOI al PIC1. Como el PIC2 es inicializado como esclavo sobre la IRQ2, cualquier solicitud usando el PIC2 no llamar&amp;aacute; a la rutina ISR para la IRQ2. El puntero de 8 bits provendr&amp;aacute; del PIC2. &lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq638"&gt;&lt;br id="z5bq639"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq640"&gt;&lt;br id="z5bq641"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq642"&gt;&lt;br id="z5bq643"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq644"&gt;&lt;br id="z5bq645"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq646"&gt;&lt;br id="z5bq647"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq648"&gt;&lt;br id="z5bq649"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq650"&gt;&lt;br id="z5bq651"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq652"&gt;&lt;br id="z5bq653"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq654"&gt;&lt;br id="z5bq655"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq656"&gt;&lt;br id="z5bq657"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq658"&gt;&lt;br id="z5bq659"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq660"&gt;&lt;br id="z5bq661"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq662"&gt;&lt;br id="z5bq663"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq664"&gt;&lt;br id="z5bq665"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq666"&gt;&lt;br id="z5bq667"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq668"&gt;&lt;br id="z5bq669"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq670"&gt;&lt;br id="z5bq671"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq672"&gt;&lt;br id="z5bq673"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq674"&gt;&lt;br id="z5bq675"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq676"&gt;&lt;br id="z5bq677"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq678"&gt;&lt;br id="z5bq679"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq680"&gt;&lt;br id="z5bq681"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq682"&gt;&lt;br id="z5bq683"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq684"&gt;&lt;br id="z5bq685"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq686"&gt;&lt;br id="z5bq687"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq688"&gt;&lt;font face="Arial, sans-serif" id="z5bq689"&gt;&lt;font id="z5bq690" size="4"&gt;&lt;b&gt;Anexo 1.B. Interrupciones en sistemas con m&amp;aacute;s de un procesador.&lt;/b&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq692"&gt;&lt;br id="z5bq693"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq694"&gt;&lt;b&gt;1.B.1 SISTEMAS SMP&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq696"&gt; El sistema SMP &amp;ndash; Symmetrical multiprocessing agrega unos pocos requerimientos al manejo de interrupciones al hardware y software respecto al sistema &amp;ldquo;normal&amp;rdquo; de UP &amp;ndash; UniProcessing. Obtener ventajas del paralelismo requiere sincronizaci&amp;oacute;n., por ejemplo s&amp;oacute;lo una CPU debe controlar una interrupci&amp;oacute;n de una cierta interrupci&amp;oacute;n de hardware. En segundo lugar, es necesario un mecanismo eficiente para pasar mensajes entre las CPUs, para planificar tareas entre las CPUs y para diferentes prop&amp;oacute;sitos de sincronizaci&amp;oacute;n. &lt;/p&gt;&lt;p class="western" id="z5bq697"&gt;&lt;br id="z5bq698"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq699"&gt;&lt;b&gt;1.B.2 APIC&lt;/b&gt;&lt;/p&gt;&lt;p class="western" id="z5bq701"&gt; Para permitir que se distribuyan completamente el control entre CPUs en un sistema SMP, Intel ha desarrollado I/O APIC (Advanced Programmable Interrupt Controller), el cu&amp;aacute;l remplaza el 8259A Programmable Interrupt Controller de los sistemas UP. &lt;/p&gt;&lt;p align="center" class="western" id="z5bq702"&gt;&lt;img align="bottom" border="0" height="260" id="z5bq703" name="graphics4" src="http://docs.google.com/File?id=dc94ptfk_21hq6nbmkg" width="328"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq704"&gt; Un APICs local posee registros de 32-bits, un clock interno, un dispositivo temporizador (timer), y dos l&amp;iacute;neas de IRQ adicionales reservadas para interrupciones locales. Las interrupciones locales son usadas t&amp;iacute;picamente para reiniciar el sistema. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq705"&gt; Las I/O APIC consisten en un conjunto de IRQs, una tabla de redirecci&amp;oacute;n de interrupciones de 24 entradas, registros programables y una unidad de mensajes para enviar y recibir mensajes APIC sobre el bus ICC (Interrupt Controler Communication). Cada entrada en la tabla de redirecci&amp;oacute;n pueden ser programadas individualmente para indicar el vector de interrupciones y la prioridad, la CPU destino y c&amp;oacute;mo se selecciona la CPU. La tabla es usada para trasladar un mensaje de cualquier IRQ externa mediante una se&amp;ntilde;al a una o m&amp;aacute;s unidades APIC locales v&amp;iacute;a el bus ICC. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq706"&gt; Las solicitudes de interrupci&amp;oacute;n pueden ser distribuidas a las CPUs de dos maneras diferentes: Modo Fijo (Fixed Mode) o Modo de Prioridad m&amp;aacute;s baja (Lowest-Priority Mode). Un rasgo importante en el APIC es que permite a las CPUs generar interrupciones entre los procesadores (interprocessor interrupts - IPIs). La CPU puede almacenar el vector de interrupciones y el identificador de los objetivos de la APIC local en el registro ICR &amp;ndash; Interrupt Local Register de su propia APIC. Entonces un mensaje es enviado por el bus ICC a la APIC local del objetivo, la cu&amp;aacute;l entonces provoca la interrupci&amp;oacute;n correspondiente a su CPU. &lt;/p&gt;&lt;p class="western" id="z5bq707"&gt; Hay soporte para m&amp;uacute;ltiples I/O APICs en el kernel &lt;font face="CMR9" id="z5bq709"&gt;2.4.18-10.&lt;/font&gt;&lt;/p&gt;&lt;h2 class="western" id="z5bq710"&gt;&lt;font face="Arial, sans-serif" id="z5bq711"&gt;&lt;font id="z5bq712" size="4"&gt;2. Tratamiento de las interrupciones&lt;/font&gt;&lt;/font&gt;&lt;/h2&gt;&lt;h2 class="western" id="z5bq713"&gt;&lt;font face="Arial, sans-serif" id="z5bq714"&gt;&lt;font id="z5bq715" size="4"&gt;2.1 Interrupt descriptor table (IDT).&lt;/font&gt;&lt;/font&gt;&lt;/h2&gt;&lt;p class="western" id="z5bq716"&gt;&lt;br id="z5bq717"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq718"&gt; Se trata de un arreglo de hasta 256 elementos (pueden ser menos) de 8 bytes cada uno. Los programadores de un sistema operativo pueden decidir ubicarlo en cualquier lugar de la memoria f&amp;iacute;sica, luego cargar&amp;aacute;n el registro &amp;ldquo;IDTR&amp;rdquo; con su direcci&amp;oacute;n y la cantidad de bytes que ocupa menos 1. La instrucci&amp;oacute;n para hacer esto es &amp;ldquo;LIDT&amp;rdquo;, pero solo puede ser ejecutada por los procesos o procedimientos que tienen el m&amp;aacute;ximo privilegio. &lt;/p&gt;&lt;p class="western" id="z5bq719"&gt; Si el vector hace referencia a una entrada m&amp;aacute;s all&amp;aacute; del l&amp;iacute;mite de la tabla, la excepci&amp;oacute;n &amp;ldquo;general-protection exception&amp;rdquo; es generada. &lt;/p&gt;&lt;p class="western" id="z5bq720"&gt;&lt;br id="z5bq721"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq722"&gt;&lt;br id="z5bq723"&gt;&lt;/p&gt;&lt;table border="0" cellpadding="5" cellspacing="0" class="zeroBorder" id="z5bq724" width="600"&gt;&lt;tbody id="z5bq726"&gt;&lt;tr id="z5bq727"&gt;&lt;td id="z5bq728" valign="top" width="590"&gt;&lt;p align="center" class="western" id="z5bq729"&gt;&lt;img align="bottom" border="0" height="325" id="z5bq730" name="graphics5" src="http://docs.google.com/File?id=dc94ptfk_22gn4b74c9" width="431"&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq731"&gt;&lt;td id="z5bq732" valign="top" width="590"&gt;&lt;p align="center" class="western" id="z5bq733"&gt;&lt;font id="z5bq734" size="2"&gt;Relaci&amp;oacute;n entre el registro IDTR y la IDT.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p class="western" id="z5bq735"&gt;&lt;br id="z5bq736"&gt;&lt;/p&gt;&lt;h2 class="western" id="z5bq737"&gt;&lt;font face="Arial, sans-serif" id="z5bq738"&gt;&lt;font id="z5bq739" size="4"&gt;2.2 Formas de atender a las interrupciones.&lt;/font&gt;&lt;/font&gt;&lt;/h2&gt;&lt;p class="western" id="z5bq740"&gt;&lt;br id="z5bq741"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq742"&gt; Los procesadores 80386 o superiores proporcionan dos formas b&amp;aacute;sicas de atender a una interrupci&amp;oacute;n dependiendo de su correspondiente entrada en la IDT, una interrupt-gate o trap-gate, o una task-gate. La diferencia es que de la primera forma no se produce un &amp;ldquo;context switch&amp;rdquo;. &lt;/p&gt;&lt;p class="western" id="z5bq743"&gt; Los siguientes campos forman parte de una interrupt-gate o trap-gate: &lt;/p&gt;&lt;ul id="z5bq744"&gt;&lt;li id="z5bq745"&gt;&lt;p align="justify" class="western" id="z5bq746"&gt; Segment selector: indica en qu&amp;eacute; segmento de memoria se encuentra la rutina que atiende a la interrupci&amp;oacute;n. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq747"&gt;&lt;p align="justify" class="western" id="z5bq748"&gt; Offset: indica en que posici&amp;oacute;n del segmento est&amp;aacute; la primera instrucci&amp;oacute;n de la rutina. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq749"&gt;&lt;p align="justify" class="western" id="z5bq750"&gt; DPL: indica cu&amp;aacute;l debe ser el privilegio para acceder a la rutina. Este campo no es tenido en cuenta por el procesador cuando la interrupci&amp;oacute;n es generada por hardware (ya sea interna o externa), sin embargo cuando la interrupci&amp;oacute;n es generada por la instrucci&amp;oacute;n &amp;ldquo;INT&amp;rdquo; es importante. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq751"&gt;&lt;p align="justify" class="western" id="z5bq752"&gt; P: indica si el segmento al que apunta el campo &amp;ldquo;Segment selector&amp;rdquo; es v&amp;aacute;lido. Si est&amp;aacute; en 0 y se produce la interrupci&amp;oacute;n, se generar&amp;aacute; una excepci&amp;oacute;n. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq753"&gt;&lt;p align="justify" class="western" id="z5bq754"&gt; D: Indica si &amp;ldquo;la gate&amp;rdquo; apunta a c&amp;oacute;digo de 32 bits o 16 bits. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;table border="0" cellpadding="5" cellspacing="0" class="zeroBorder" id="z5bq755" width="600"&gt;&lt;tbody id="z5bq757"&gt;&lt;tr id="z5bq758"&gt;&lt;td id="z5bq759" valign="top" width="590"&gt;&lt;p align="center" class="western" id="z5bq760"&gt;&lt;img align="bottom" border="0" height="300" id="z5bq761" name="graphics6" src="http://docs.google.com/File?id=dc94ptfk_23c57kmffd" width="421"&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq762"&gt;&lt;td id="z5bq763" valign="top" width="590"&gt;&lt;p align="center" class="western" id="z5bq764"&gt;&lt;font id="z5bq765" size="2"&gt;Las estructuras de la interrupt-gate y de la trap-gate.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p class="western" id="z5bq766"&gt;&lt;br id="z5bq767"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq768"&gt; Cuando una interrupci&amp;oacute;n ocurre y en la entrada de la IDT hay una iterrupt-gate o trap-gate el procesador guarda en la pila los flags, la direcci&amp;oacute;n de la instrucci&amp;oacute;n que se iba a ejecutar (determinada por los registros CS y EIP) y el c&amp;oacute;digo de error (si existe), en ese orden. Luego salta al procedimiento que atender&amp;aacute; la interrupci&amp;oacute;n. Si se trata de una interrupt-gate las interrupciones se deshabilitar&amp;aacute;n autom&amp;aacute;ticamente, se obtendr&amp;iacute;a el mismo efecto si se pusiera una trap-gate y luego se invocara a la instrucci&amp;oacute;n &amp;ldquo;CLI&amp;rdquo; (clear interrupt flag) al comienzo de la rutina que atiende la interrupci&amp;oacute;n. Es responsabilidad de la persona que program&amp;oacute; esta rutina preservar el estado de todos los registros. Al finalizar se deber&amp;aacute; volver al procedimiento que se estaba ejecutando, mediante la instrucci&amp;oacute;n &amp;ldquo;IRET&amp;rdquo; (esta instrucci&amp;oacute;n es similar a &amp;ldquo;RET&amp;rdquo;, con la &amp;uacute;nica diferencia que tambi&amp;eacute;n restaurar&amp;aacute; los flags). &lt;/p&gt;&lt;p class="western" id="z5bq769"&gt;&lt;br id="z5bq770"&gt;&lt;/p&gt;&lt;table border="0" cellpadding="5" cellspacing="0" class="zeroBorder" id="z5bq771" width="600"&gt;&lt;tbody id="z5bq773"&gt;&lt;tr id="z5bq774"&gt;&lt;td id="z5bq775" valign="top" width="590"&gt;&lt;p align="center" class="western" id="z5bq776"&gt;&lt;img align="bottom" border="0" height="190" id="z5bq777" name="graphics7" src="http://docs.google.com/File?id=dc94ptfk_24gzmz3scz" width="314"&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq778"&gt;&lt;td id="z5bq779" valign="top" width="590"&gt;&lt;p align="center" class="western" id="z5bq780"&gt;&lt;font id="z5bq781" size="2"&gt;La pila antes y luego de que se produzca una interrupci&amp;oacute;n atendida por una interrupt-gate o trap-gate.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p class="western" id="z5bq782"&gt;&lt;br id="z5bq783"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq784"&gt; Si en la entrada hay una task-gate la interrupci&amp;oacute;n ser&amp;aacute; atendida por otro proceso, entonces se produce un context switch. En este caso el procesador realiza las siguientes tareas: &lt;/p&gt;&lt;ul id="z5bq785"&gt;&lt;li id="z5bq786"&gt;&lt;p align="justify" class="western" id="z5bq787"&gt; Todos los registros de la CPU que contienen informaci&amp;oacute;n que le corresponde al proceso en ejecuci&amp;oacute;n son salvados autom&amp;aacute;ticamente. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq788"&gt;&lt;p align="justify" class="western" id="z5bq789"&gt; La informaci&amp;oacute;n necesaria para que el procesador sepa hacia qu&amp;eacute; proceso volver cuando termine de atender la interrupci&amp;oacute;n es almacenada. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq790"&gt;&lt;p align="justify" class="western" id="z5bq791"&gt; El flag &amp;ldquo;NT&amp;rdquo; (nested task) se pone en 1 para indicar que hay una anidaci&amp;oacute;n de procesos (informaci&amp;oacute;n que ser&amp;aacute; necesaria para la intrucci&amp;oacute;n &amp;ldquo;IRET&amp;rdquo;). &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq793"&gt;&lt;p align="justify" class="western" id="z5bq794"&gt; El proceso en ejecuci&amp;oacute;n toma el estado de &amp;ldquo;BUSY&amp;rdquo; (ocupado), significa que no podr&amp;aacute; continuar hasta que termine el que atiende a la interrupci&amp;oacute;n. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq795"&gt;&lt;p align="justify" class="western" id="z5bq796"&gt; Los registros son cargados con la informaci&amp;oacute;n que le corresponde al nuevo proceso y comienza la ejecuci&amp;oacute;n. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="western" id="z5bq797"&gt;&lt;br id="z5bq798"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq799"&gt; Al terminar se deber&amp;aacute; volver con la instrucci&amp;oacute;n &amp;ldquo;IRET&amp;rdquo;, que producir&amp;aacute; un context switch al verificar que el flag &amp;ldquo;NT&amp;rdquo; est&amp;aacute; en 1. &lt;/p&gt;&lt;p class="western" id="z5bq800"&gt; Los siguientes campos forman parte de una task-gate: &lt;/p&gt;&lt;ul id="z5bq801"&gt;&lt;li id="z5bq802"&gt;&lt;p align="justify" class="western" id="z5bq803"&gt; Segment selector: indica el segmento que contiene informaci&amp;oacute;n acerca del proceso. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq804"&gt;&lt;p align="justify" class="western" id="z5bq805"&gt; DPL: indica cu&amp;aacute;l debe ser el privilegio para hacer un context switch hacia el proceso. Este campo no es tenido en cuenta por el procesador cuando la interrupci&amp;oacute;n es generada por hardware (ya sea interna o externa), sin embargo cuando la interrupci&amp;oacute;n es generada por la instrucci&amp;oacute;n &amp;ldquo;INT&amp;rdquo; es importante. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq806"&gt;&lt;p align="justify" class="western" id="z5bq807"&gt; P: indica si el segmento al que apunta el campo &amp;ldquo;Segment selector&amp;rdquo; es v&amp;aacute;lido. Si est&amp;aacute; en 0 y se produce la interrupci&amp;oacute;n, se generar&amp;aacute; una excepci&amp;oacute;n. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="western" id="z5bq808"&gt;&lt;br id="z5bq809"&gt;&lt;/p&gt;&lt;table border="0" cellpadding="5" cellspacing="0" class="zeroBorder" id="z5bq810" width="600"&gt;&lt;tbody id="z5bq812"&gt;&lt;tr id="z5bq813"&gt;&lt;td id="z5bq814" valign="top" width="590"&gt;&lt;p align="center" class="western" id="z5bq815"&gt;&lt;img align="bottom" border="0" height="154" id="z5bq816" name="graphics8" src="http://docs.google.com/File?id=dc94ptfk_25xjvvvddz" width="424"&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq817"&gt;&lt;td id="z5bq818" valign="top" width="590"&gt;&lt;p align="center" class="western" id="z5bq819"&gt;&lt;font id="z5bq820" size="2"&gt;La estructura de la task-gate.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p class="western" id="z5bq821"&gt;&lt;br id="z5bq822"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq823"&gt; Las ventajas que ofrece atender una interrupci&amp;oacute;n con otro proceso son que todos los registros son salvados autom&amp;aacute;ticamente y que la rutina puede ser aislada otorg&amp;aacute;ndole un espacio de direcciones l&amp;oacute;gicas distinto. Por otro lado la cantidad de informaci&amp;oacute;n que el procesador guarda autom&amp;aacute;ticamente en el context switch hace que pueda ser una opci&amp;oacute;n mucho m&amp;aacute;s lenta que la interrupt-gate o trap-gate. &lt;/p&gt;&lt;p class="western" id="z5bq824"&gt;&lt;br id="z5bq825"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq826"&gt;&lt;b&gt;2.3 Inicializando la IDT&lt;/b&gt;&lt;/p&gt;&lt;p class="western" id="z5bq828"&gt;&lt;br id="z5bq829"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq830"&gt; Antes de que el Kernel habilite una interrupci&amp;oacute;n, debe cargar la direcci&amp;oacute;n inicial de la IDT en el registro &lt;b&gt;idtr&lt;/b&gt; e inicializar todas las entradas de la tabla. Linux usa las interrupts gates para controlar interrupciones y las trap gates para controlar excepciones. Linux no usa task gates. &lt;/p&gt;&lt;p class="western" id="z5bq832" style="margin-left:0.25in"&gt;&lt;br id="z5bq833"&gt;&lt;/p&gt;&lt;ul id="z5bq834"&gt;&lt;li id="z5bq835"&gt;&lt;p class="western" id="z5bq836"&gt;&lt;b&gt;Interrupt Gate: &lt;/b&gt;Todos los controladores de interrupciones. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id="z5bq838"&gt;&lt;li id="z5bq839"&gt;&lt;p class="western" id="z5bq840"&gt;&lt;b&gt;System Gate: &lt;/b&gt;4 controladores de excepciones (3,4,5 y el vector 128) &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id="z5bq842"&gt;&lt;li id="z5bq843"&gt;&lt;p class="western" id="z5bq844"&gt;&lt;b&gt;Trap Gate: &lt;/b&gt;Todos los controladores de excepciones excepto el 4. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id="z5bq846"&gt;&lt;li id="z5bq847"&gt;&lt;p class="western" id="z5bq848"&gt; Insertar los gates en la IDT &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id="z5bq849"&gt;&lt;ul id="z5bq850"&gt;&lt;li id="z5bq851"&gt;&lt;p class="western" id="z5bq852"&gt; set_intr_gate(n, addr) &lt;/p&gt;&lt;/li&gt;&lt;ul id="z5bq853"&gt;&lt;li id="z5bq854"&gt;&lt;p class="western" id="z5bq855"&gt; Inserta una interrupt gate, el campo DPL (Descriptor Privilege Level = 0), entonces no puede ser accedido por programas en modo usuario. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li id="z5bq856"&gt;&lt;p class="western" id="z5bq857"&gt; set_system_gate(n, addr) &lt;/p&gt;&lt;/li&gt;&lt;ul id="z5bq858"&gt;&lt;li id="z5bq859"&gt;&lt;p class="western" id="z5bq860"&gt; Inserta una system gate, el campo DPL = 3, esto significa que pueden ser accedidas por programas en modo usuario. Por ejemplo, en Linux, el vector 128 accedido por una system call iniciada por una INT 0x80. La INT3, INTO, BOUND y la INT 0x80 pueden ser accedidas por procesos en modo usuario. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li id="z5bq861"&gt;&lt;p class="western" id="z5bq862"&gt; set_trap_gate(n, addr) &lt;/p&gt;&lt;/li&gt;&lt;ul id="z5bq863"&gt;&lt;li id="z5bq864"&gt;&lt;p class="western" id="z5bq865"&gt; Inserta una trap gate, DPL = 0. Son usadas para activar las rutinas de atenci&amp;oacute;n a excepciones. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;p class="western" id="z5bq866"&gt;&lt;br id="z5bq867"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq868"&gt; Estas funciones insertan el gate descriptor en la n-&amp;eacute;sima entrada de la IDT. El par&amp;aacute;metro &lt;b&gt;addr &lt;/b&gt;identifica el desplazamiento (offset) del segmento en el c&amp;oacute;digo del Kernel, el cual es la direcci&amp;oacute;n base de la rutina de atenci&amp;oacute;n. Ejemplo &lt;/p&gt;&lt;p class="western" id="z5bq870"&gt;&lt;b&gt;se&lt;font color="#000000" id="z5bq873"&gt;&lt;font face="Courier New, monospace" id="z5bq874"&gt;t_system_gate(0x80, &amp;amp;system_call); &lt;/font&gt;&lt;/font&gt;&lt;/b&gt;&lt;font color="#000000" id="z5bq876"&gt;&lt;i&gt;(en sched.c y traps.c)&lt;/i&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq878"&gt;&lt;br id="z5bq879"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq880"&gt;&lt;br id="z5bq881"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq882"&gt;&lt;br id="z5bq883"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq884"&gt;&lt;br id="z5bq885"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq886"&gt;&lt;br id="z5bq887"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq888"&gt;&lt;br id="z5bq889"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq890"&gt;&lt;br id="z5bq891"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq892"&gt;&lt;br id="z5bq893"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq894"&gt;&lt;br id="z5bq895"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq896"&gt;&lt;br id="z5bq897"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq898"&gt;&lt;br id="z5bq899"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq900"&gt;&lt;br id="z5bq901"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq902"&gt;&lt;br id="z5bq903"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq904"&gt;&lt;br id="z5bq905"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq906"&gt;&lt;br id="z5bq907"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq908"&gt;&lt;br id="z5bq909"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq910"&gt;&lt;br id="z5bq911"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq912"&gt;&lt;br id="z5bq913"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq914"&gt;&lt;br id="z5bq915"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq916"&gt;&lt;br id="z5bq917"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq918"&gt;&lt;br id="z5bq919"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq920"&gt;&lt;br id="z5bq921"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq922"&gt;&lt;br id="z5bq923"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq924"&gt;&lt;br id="z5bq925"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq926"&gt;&lt;br id="z5bq927"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq928"&gt;&lt;br id="z5bq929"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq930"&gt;&lt;br id="z5bq931"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq932"&gt;&lt;br id="z5bq933"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq934"&gt;&lt;br id="z5bq935"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq936"&gt;&lt;br id="z5bq937"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq938"&gt;&lt;br id="z5bq939"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq940"&gt;&lt;br id="z5bq941"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq942"&gt;&lt;font face="Arial, sans-serif" id="z5bq943"&gt;&lt;font id="z5bq944" size="4"&gt;&lt;b&gt;Anexo 2.A. Interrupciones en Linux.&lt;/b&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq946"&gt;&lt;br id="z5bq947"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq948"&gt;&lt;b&gt;2.A.1 Linux System Calls&lt;/b&gt;&lt;/p&gt;&lt;p class="western" id="z5bq950"&gt;&lt;br id="z5bq951"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq952"&gt; Se invocan ejecutando &lt;b&gt;int $0x80&lt;/b&gt;, quiere decir que: &lt;/p&gt;&lt;ul id="z5bq954"&gt;&lt;ul id="z5bq955"&gt;&lt;li id="z5bq956"&gt;&lt;p class="western" id="z5bq957"&gt; El n&amp;uacute;mero de vector de excepciones programadas es el 128. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;ul id="z5bq958"&gt;&lt;ul id="z5bq959"&gt;&lt;li id="z5bq960"&gt;&lt;p class="western" id="z5bq961"&gt; La CPU cambia al modo kernel y ejecuta la funci&amp;oacute;n del kernel. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li id="z5bq962"&gt;&lt;p class="western" id="z5bq963"&gt; El proceso llamado pasa el n&amp;uacute;mero de system call (&lt;b&gt;syscall number&lt;/b&gt;) identificando al system call en el registro &lt;b&gt;eax&lt;/b&gt; (en los procesadores Intel). &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq966"&gt;&lt;p class="western" id="z5bq967"&gt; El controlador syscall es responsable de: &lt;/p&gt;&lt;/li&gt;&lt;ul id="z5bq968"&gt;&lt;li id="z5bq969"&gt;&lt;p class="western" id="z5bq970"&gt; Guardar los registros en la pila en modo kernel. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq971"&gt;&lt;p class="western" id="z5bq972"&gt; Invocar a la rutina de servicio de la syscall. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq973"&gt;&lt;p class="western" id="z5bq974"&gt; Salir llamando &lt;b&gt;ret_from_sys_call().&lt;/b&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li id="z5bq976"&gt;&lt;p class="western" id="z5bq977"&gt; La tabla para enviar system calls: &lt;/p&gt;&lt;/li&gt;&lt;ul id="z5bq978"&gt;&lt;li id="z5bq979"&gt;&lt;p class="western" id="z5bq980"&gt; Asocia un n&amp;uacute;mero de syscall con la rutina de servicio correspondiente, &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq981"&gt;&lt;p class="western" id="z5bq982"&gt; Almacenada en el arrar sys_call_table tiene NR_syscall entradas (256 m&amp;aacute;ximo, el linux 2.4.18 tiene 237). &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq983"&gt;&lt;p class="western" id="z5bq984"&gt; El n-&amp;eacute;simo registro contiene la direcci&amp;oacute;n de la rutina de servicio de la syscall n. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;p class="western" id="z5bq985"&gt;&lt;br id="z5bq986"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq987"&gt;&lt;b&gt;2.A.2 Iniciando las System Calls&lt;/b&gt;&lt;/p&gt;&lt;p id="z5bq989"&gt;&lt;br id="z5bq990"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq991"&gt; Cuando el sistema bootea, es llamada la funci&amp;oacute;n &lt;font color="#000000" id="z5bq992"&gt;arch/i386/kernel/traps.c:&lt;b&gt;trap_init(), &lt;/b&gt;esta coloca la entrada correspondiente al vector 0x80 (tipo 15, DPL 3) en la IDT (&lt;/font&gt;&lt;b&gt;set_system_gate(0x80, &amp;amp;system_call);)&lt;/b&gt;, apuntando a la direcci&amp;oacute;n de la system_call en &lt;font color="#000000" id="z5bq996"&gt;arch/i386/kernel/entry.S. &lt;/font&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq997"&gt; Cuando una aplicaci&amp;oacute;n en espacio de usuario hace una system call, los argumentos son pasados v&amp;iacute;a registro y la aplicaci&amp;oacute;n ejecuta la instrucci&amp;oacute;n &amp;lsquo;int 0x80&amp;rsquo;. Esto causa una trap, se pasa a modo kernel, y el procesador salta a la system_call apuntada en entry.S. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq998"&gt;&lt;br id="z5bq999"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1000"&gt;&lt;b&gt;2.A.3 System Calls Est&amp;aacute;ticas&lt;/b&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1002"&gt;&lt;br id="z5bq1003"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1004"&gt;&lt;font color="#000000" id="z5bq1005"&gt;Una de las caracter&amp;iacute;sticas m&amp;aacute;s importantes de Unix es la clara distinci&amp;oacute;n entre el &amp;ldquo;espacio del kernel&amp;rdquo; y el &amp;ldquo;espacio del usuario&amp;rdquo;. Linux ofrece a los procesos que corren en el espacio del usuario un conjunto de interfaces para interactuar con dispositivos hardware como la CPU, discos, impresoras, etc. El sistema Linux implementa la mayor&amp;iacute;a de las interfaces entre procesos en modo usuario y dispositivos hardware con las llamadas System Calls emitidas al kernel. Una de las &amp;uacute;ltimas versiones del Kernel de Linux (versi&amp;oacute;n 2.4.18) tiene 237 system calls. Las system calls pueden ser llamadas tambi&amp;eacute;n &lt;b&gt;System Request&lt;/b&gt; o &lt;b&gt;syscall&lt;/b&gt;.&lt;/font&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1008"&gt; En general, se supone que proceso no posee acceso al kernel. No puede acceder a la memoria del kernel y no puede llamar a funciones del kernel. El hardware de la CPU hace esto posible (esta forma de control se llama &amp;ldquo;modo protegido&amp;rdquo;). &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1009"&gt; Las System calls son una excepci&amp;oacute;n a esta regla. Un proceso llena registros con los valores apropiados y entonces, llama a una instrucci&amp;oacute;n especial que salta a una direcci&amp;oacute;n definida en el Kernel. En las CPUs de Intel, esto es posible por la llamada interrupt 0x80. El hardware sabe que una vez que se salta a esta direcci&amp;oacute;n, no se est&amp;aacute; corriendo en el restringido modo de usuario. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1010"&gt; Para indicar al kernel el n&amp;uacute;mero de la system call, debe almacenarse dicho n&amp;uacute;mero en el registro EAX. Antes de cambiar al modo kernel, el procesador debe guardar todos los registros y derivarle la ejecuci&amp;oacute;n a la funci&amp;oacute;n del kernel apropiada, antes debe verificar que EAX no est&amp;eacute; fuera de rango. El archivo uniste.h contiene los n&amp;uacute;meros de las system calls. &lt;/p&gt;&lt;p class="western" id="z5bq1011"&gt;&lt;br id="z5bq1012"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1013"&gt;&lt;b&gt;2.A.4 Bottom Halves&lt;/b&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1015"&gt;&lt;br id="z5bq1016"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1017"&gt; Bottom halves son la forma en que Linux retrasa el procesamiento. Se usan en los controladores de interrupciones. En un controlador de interrupciones, no se procesan otras interrupciones o eventos de ninguna clase mientras este se est&amp;aacute; ejecutando (las interrupciones son deshabilitadas), Si se quiere poder atender otras interrupciones mientras el controlador se est&amp;aacute; ejecutando y dejar el resto de la manipulaci&amp;oacute;n para m&amp;aacute;s tarde (porque consume mucho tiempo), pero antes que el retorno al espacio de usuario, se debe crear una bottom half. A una Bottom Half tambi&amp;eacute;n se la conoce como softirq. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1018"&gt; Uno de los principales problemas con el manejo de las interrupciones es como realizar largas tareas dentro de un controlador de interrupciones. A veces, se necesita hacer un trabajo considerable como respuesta a una interrupci&amp;oacute;n de un dispositivo, pero un controlador de interrupciones debe terminar r&amp;aacute;pidamente y no mantener bloqueadas las interrupciones por mucho tiempo. Estas dos necesidades (mucho trabajo y velocidad) entran en conflicto mutuamente. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1019"&gt; La soluci&amp;oacute;n a este problema es dejar para el controlador de interrupciones lo inmediatamente necesario, usualmente leer algo del hardware o enviar algo al hardware, y entonces programar el control de nueva informaci&amp;oacute;n para m&amp;aacute;s tarde (en la &amp;ldquo;bottom half&amp;rdquo;) y retornar del controlador. El Kernel garantiza entonces que llamar&amp;aacute; a la bottom half tan pronto como sea posible, antes que se retorne a modo usuario, y cuando hace esto, todo lo permitido a los m&amp;oacute;dulos del kernel estar&amp;aacute; permitido ahora. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1020"&gt; As&amp;iacute; los controladores de interrupciones est&amp;aacute;n divididos en dos partes: una top y una bottom half (mitad de arriba y mitad de abajo). La top half es el verdadero controlador de interrupciones: a veces solo le dice al kernel que ejecute la bottom half, y sale. El kernel garantiza que la top half nunca reentrar&amp;aacute;. Si llega otra interrupci&amp;oacute;n, ser&amp;aacute; encolada hasta que la top half termine. Como la top half deshabilita las interrupciones, debe ser r&amp;aacute;pida. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1021"&gt; La bottom half correr&amp;aacute; antes que otra interrupci&amp;oacute;n sea procesada, o su tiempo se haya terminado. Las interrupciones no son deshabilitadas mientras una bottom half est&amp;aacute; corriendo, entonces estas pueden hacer trabajos &amp;ldquo;lentos&amp;rdquo;. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1022"&gt;&lt;br id="z5bq1023"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1024"&gt;&lt;b&gt;2.A.5 Implementaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1026"&gt;&lt;br id="z5bq1027"&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1028"&gt; Puede haber hasta 32 controladores bottom half diferentes; bh_base es un vector de punteros a cada una de las rutinas bottom half del kernel; bh_active y bh_mask tienen los bits colocados (activados) de acuerdo a que controladores han sido instalados y cuales est&amp;aacute;n activos. Si el bit N de bh_mask est&amp;aacute; colocado, entonces el N-&amp;eacute;simo elemento de bh_base contiene la direcci&amp;oacute;n de la rutina bottom half. Si el bit N de bh_active est&amp;aacute; colocado, entonces la N-&amp;eacute;sima rutina bottom half debe ser llamada tan pronto como el planificador crea razonable. Estos &amp;iacute;ndices son definidos est&amp;aacute;ticamente, la rutina bottom half del timer posee la priridad m&amp;aacute;s alta (&amp;iacute;ndice 0), la rutina bottom half de la consola es la pr&amp;oacute;xima en prioridad (&amp;iacute;ndice 1), etc. &lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1029"&gt;&lt;font color="#000000" id="z5bq1030"&gt; Algunas de las rutinas bottom half del kernel son espec&amp;iacute;ficas del dispositivo, pero otras son m&amp;aacute;s gen&amp;eacute;ricas. Por ejemplo, el controlador del TIMER es marcado como activo cada vez que el timer del sistema interrumpe y es usado para manejar los mecanismos de cola del temporizador del kernel.&lt;/font&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1031"&gt;&lt;font color="#000000" id="z5bq1032"&gt; Cada vez que un controlador de dispositivos, o alguna otra parte del kernel, necesita planificar trabajo para ser hecho despu&amp;eacute;s, este a&amp;ntilde;ade trabajo a la cola del sistema apropiada, por ejemplo a la cola del timer, y entonces le indica al kernel que alguna rutina bottom half necesitar ser hecha. Esto lo hace colocando el bit apropiado en bh_active. El bit 8 es colocado si el controlador ha encolado algo en la cola inmediata y desea que se ejecute y se procese el controlador bottom half inmediato. La m&amp;aacute;scara de bits bh_active es verificada al final de cada system call, justo antes que el control sea devuelto al proceso llamador. Si hay alg&amp;uacute;n bit colocado, las rutinas bottom half activas son llamadas. Primero se verifica el bit 0, luego el bit 1, y as&amp;iacute; hasta el bit 31.&lt;/font&gt;&lt;/p&gt;&lt;p align="justify" class="western" id="z5bq1034"&gt; Cada vez que una rutina de la bottom half es llamada el bit en bh_active es borrado. As&amp;iacute;, cada activaci&amp;oacute;n s&amp;oacute;lo causa una ejecuci&amp;oacute;n. bh_active es transitorio; s&amp;oacute;lo tiene significado entre llamadas al planificador (scheduler) y es una forma de no llamar rutinas bottom half cuando no tienen trabajo que hacer. &lt;/p&gt;&lt;p align="justify" id="z5bq1035"&gt;&lt;font color="#000000" id="z5bq1036"&gt;Las Bottom halves que est&amp;aacute;n esperando ser&amp;aacute;n ejecutadas s&amp;oacute;lo cuando uno de los siguientes eventos ocurre:&lt;/font&gt;&lt;/p&gt;&lt;ul id="z5bq1038"&gt;&lt;li id="z5bq1039"&gt;&lt;p align="justify" id="z5bq1040"&gt; El kernel finaliza la atenci&amp;oacute;n de una excepci&amp;oacute;n. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq1041"&gt;&lt;p align="justify" id="z5bq1042"&gt; El kernel finaliza la atenci&amp;oacute;n de una system call. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq1043"&gt;&lt;p align="justify" id="z5bq1044"&gt; El kernel finaliza la atenci&amp;oacute;n de una interrupci&amp;oacute;n. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq1045"&gt;&lt;p align="justify" id="z5bq1046"&gt; El kernel ejecuta la funci&amp;oacute;n schedule() para seleccionar un nuevo proceso. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p align="justify" id="z5bq1047" style="margin-left:0.25in"&gt;&lt;br id="z5bq1048"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1049"&gt;&lt;b&gt;2.A.6 Ejemplo&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1051"&gt;&lt;br id="z5bq1052"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1053"&gt; El kernel necesita un sistema de sincronizaci&amp;oacute;n para: mantener la cuenta de la hora y fecha para ser usada por ejemplo por gettimeofday(), y mantener el temporizador que notifica al kernel o a un programa de usuario que un intervalo de tiempo ha terminado. &lt;/p&gt;&lt;p align="justify" id="z5bq1054"&gt;&lt;font color="#000000" id="z5bq1055"&gt;Cada interrupci&amp;oacute;n del timer: Actualiza los &amp;ldquo;momentos&amp;rdquo; (jiffies); Actualiza la hora y fecha; Determina cuanto tiempo un proceso se ha estado ejecutando y lo precede su porci&amp;oacute;n de tiempo ha terminado; Actualiza las estad&amp;iacute;sticas de los recursos usados; Invoca funciones para intervalos de tiempo terminados.&lt;/font&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1057"&gt;&lt;font color="#000000" id="z5bq1058"&gt;Cuando una se&amp;ntilde;al sobre la IRQ 0 es generada, se invoca timer_interrupt(), deshabilitando las interrupciones (la flag SA_INTERRUPT es activada para indicarlo). Finalmente do_timer() es ejecutada. Simplemente incrementa los &amp;ldquo;momentos&amp;rdquo; y asigna otras tareas a los controladores bottom half. Las bottom half actualizan la fecha y hora, estad&amp;iacute;sticas, ejecuta sus funciones antes que su intervalo de tiempo finalice e invoca schedule() si es necesario, para replanificar procesos.&lt;/font&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1060"&gt; do_timer() corre con las interrupciones deshabilitadas, y debe ser ejecutado lo m&amp;aacute;s r&amp;aacute;pidamente posible. Esta simplemente actualiza un valor fundamental mientras que delega otras actividades a dos bottom halves. &lt;/p&gt;&lt;p align="justify" id="z5bq1061"&gt; La timer_bh() asociada con la bottom half TIMER_BH invoca la update_times() y run_timer_list(). &lt;/p&gt;&lt;p align="justify" id="z5bq1062"&gt; La funci&amp;oacute;n update_times() invocada por la bottom half TIMER_BH actualiza xtime deshabilitando las interrupciones. &lt;/p&gt;&lt;p align="justify" id="z5bq1063"&gt; Cada vez que alg&amp;uacute;n c&amp;oacute;digo quiere planificar una bottom half para que sea ejecutada, este llama a mark_bh. En la vieja implementaci&amp;oacute;n de BH, mark_bh colocaba un bit en la m&amp;aacute;scara, permitiendo a la correspondiente rutina bottom half ser encontrada r&amp;aacute;pidamente en tiempo de ejecuci&amp;oacute;n. En los kernel modernos, esta s&amp;oacute;lo llama traklet_schedule para planificar la rutina de bottom half para la ejecuci&amp;oacute;n. &lt;/p&gt;&lt;p align="justify" id="z5bq1064"&gt;&lt;br id="z5bq1065"&gt;&lt;/p&gt;&lt;table border="1" bordercolor="#000000" cellpadding="5" cellspacing="0" id="z5bq1066" width="601"&gt;&lt;tbody id="z5bq1068"&gt;&lt;tr id="z5bq1069"&gt;&lt;td id="z5bq1070" valign="top" width="589"&gt;&lt;p align="center" class="western" id="z5bq1071"&gt;&lt;img align="bottom" border="0" height="216" id="z5bq1072" name="graphics9" src="http://docs.google.com/File?id=dc94ptfk_26g4mbs8g4" width="303"&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq1073"&gt;&lt;td id="z5bq1074" valign="top" width="589"&gt;&lt;p align="center" class="western" id="z5bq1075"&gt;&lt;font id="z5bq1076" size="2"&gt;Divisi&amp;oacute;n entre espacios de usuario y de kernel.&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p align="center" class="western" id="z5bq1077"&gt;&lt;br id="z5bq1078"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1079"&gt; Un ejemplo de uso para las Bottom half es en las interfaces de red: una Top Half obtiene el paquete de datos y la top half la procesa. &lt;/p&gt;&lt;p align="justify" id="z5bq1080"&gt;&lt;br id="z5bq1081"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1082"&gt;&lt;b&gt;2.A.7 Interrupciones de Software&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1084"&gt;&lt;br id="z5bq1085"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1086"&gt; La diferencia entre software interrupts y bottom halves es que las bottom halves son estrictamente serializadas (2 bottom halves no pueden ser ejecutadas al mismo tiempo), las software interrupt no es serializada, as&amp;iacute; se da la posibilidad de correr 2 mismas interrupciones en 2CPUs, en este caso una software interrupt puede ser reentrante. &lt;/p&gt;&lt;p align="justify" id="z5bq1087"&gt;&lt;br id="z5bq1088"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1089"&gt;&lt;b&gt;2.A.8 Tasklet&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1091"&gt;&lt;br id="z5bq1092"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1093"&gt; Es un mecanismo similar a las bottom half, construidas sobre las software interrupts pero serializadas. 2 CPU pueden ejecutar 2 tasklets al mismo tiempo, pero esas tasklet deben ser diferentes. &lt;/p&gt;&lt;p align="justify" id="z5bq1094"&gt;&lt;br id="z5bq1095"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1096"&gt;&lt;b&gt;2.A.9 LINUX 2.4 Bottom Half&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1098"&gt; Las Bottom half contin&amp;uacute;an en Linux 2.4, pero son construidas sobre las tasklets. No pueden correr al mismo tiempo en diferentes CPU, esto degrada el rendimiento significativamente de sistemas multiprocesadores. &lt;/p&gt;&lt;p align="justify" id="z5bq1099"&gt;&lt;br id="z5bq1100"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1101"&gt;&lt;b&gt;2.A.10 Colas de Tareas&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1103"&gt; Las colas de tareas pueden ser pensadas como extensiones din&amp;aacute;micas de las viejas bottom halves. &lt;/p&gt;&lt;p align="justify" id="z5bq1104"&gt;&lt;br id="z5bq1105"&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1106"&gt;&lt;b&gt;2.A.11 Beneficios de usar Bottom Halves&lt;/b&gt;&lt;/p&gt;&lt;p align="justify" id="z5bq1108"&gt;&lt;br id="z5bq1109"&gt;&lt;/p&gt;&lt;ul id="z5bq1110"&gt;&lt;li id="z5bq1111"&gt;&lt;p align="justify" id="z5bq1112"&gt;&lt;font color="#000000" id="z5bq1113"&gt;Las Bottom halves son el mecanismo m&amp;aacute;s viejo para diferir la ejecuci&amp;oacute;n de tareas al kernel y est&amp;aacute;n disponibles desde el Linux 1.x.&lt;/font&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq1114"&gt;&lt;p align="justify" id="z5bq1115"&gt; La existencia de las bottom halves es muy importante para realizar responsabilidades del kernel atendiendo interrupciones de m&amp;uacute;ltiples dispositivos r&amp;aacute;pidamente. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq1116"&gt;&lt;p align="justify" id="z5bq1117"&gt; Los controladores de dispositivos y otras partes del kernel de linux pueden encolar el trabajo por hacer. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="western" id="z5bq1118"&gt;&lt;br id="z5bq1119"&gt;&lt;/p&gt;&lt;h1 class="western" id="z5bq1120"&gt;&lt;font id="z5bq1121" size="4"&gt;Anexo 2.B. Programa de ejemplo.&lt;/font&gt;&lt;/h1&gt;&lt;p class="western" id="z5bq1122"&gt;&lt;br id="z5bq1123"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1124"&gt; Es un programa muy sencillo que muestra c&amp;oacute;mo se construye la IDT, c&amp;oacute;mo se inicializan los 8259 y c&amp;oacute;mo se hacen las rutinas para atender a las interrupciones. Lo &amp;uacute;nico que hace es esperar que pasen 20 segundos aproximadamente o que el usuario presione la tecla ESC. Consta de funciones escritas en C y en assembler y est&amp;aacute; hecho para correr en modo real (aunque luego pase a modo protegido), por eso es conveniente enlazarlo para DOS. &lt;/p&gt;&lt;p class="western" id="z5bq1125"&gt;&lt;br id="z5bq1126"&gt;&lt;/p&gt;&lt;table border="1" bordercolor="#000000" cellpadding="5" cellspacing="0" frame="below" id="z5bq1127" width="600"&gt;&lt;tbody id="z5bq1129"&gt;&lt;tr id="z5bq1130"&gt;&lt;td id="z5bq1131" valign="top" width="590"&gt;&lt;p class="western" id="z5bq1132"&gt; Archivo: ejprog.asm &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq1133"&gt;&lt;td id="z5bq1134" valign="top" width="590"&gt;&lt;p class="western" id="z5bq1135"&gt;&lt;font face="Courier New, monospace" id="z5bq1136"&gt;&lt;font id="z5bq1138" size="1"&gt;GLOBAL _read_cr0, _write_cr0, _lgdt, _lidt, _update_cs, _enable, _disable, \&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1139"&gt;&lt;font face="Courier New, monospace" id="z5bq1140"&gt;&lt;font id="z5bq1142" size="1"&gt; _timer_isr, _kbd_isr&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1143"&gt;&lt;br id="z5bq1144"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1145"&gt;&lt;font face="Courier New, monospace" id="z5bq1146"&gt;&lt;font id="z5bq1148" size="1"&gt;EXTERN _timer_handler, _kbd_handler&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1149"&gt;&lt;br id="z5bq1150"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1151"&gt;&lt;font face="Courier New, monospace" id="z5bq1152"&gt;&lt;font id="z5bq1154" size="1"&gt;SEGMENT _TEXT PUBLIC CLASS=CODE USE16&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1155"&gt;&lt;br id="z5bq1156"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1157"&gt;&lt;font face="Courier New, monospace" id="z5bq1158"&gt;&lt;font id="z5bq1160" size="1"&gt;_read_cr0: ; devuelve el contenido del registro cr0&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1161"&gt;&lt;font face="Courier New, monospace" id="z5bq1162"&gt;&lt;font id="z5bq1164" size="1"&gt;mov eax, cr0&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1165"&gt;&lt;font face="Courier New, monospace" id="z5bq1166"&gt;&lt;font id="z5bq1168" size="1"&gt;mov edx, eax&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1169"&gt;&lt;font face="Courier New, monospace" id="z5bq1170"&gt;&lt;font id="z5bq1172" size="1"&gt;shr edx, 16&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1173"&gt;&lt;font face="Courier New, monospace" id="z5bq1174"&gt;&lt;font id="z5bq1176" size="1"&gt;retn ; dx:ax es contienen los datos que se devuelven&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1177"&gt;&lt;br id="z5bq1178"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1179"&gt;&lt;font face="Courier New, monospace" id="z5bq1180"&gt;&lt;font id="z5bq1182" size="1"&gt;_write_cr0: ; carga el registro cr0 con el par&amp;aacute;metro&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1183"&gt;&lt;font face="Courier New, monospace" id="z5bq1184"&gt;&lt;font id="z5bq1186" size="1"&gt;push bp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1187"&gt;&lt;font face="Courier New, monospace" id="z5bq1188"&gt;&lt;font id="z5bq1190" size="1"&gt;mov bp, sp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1191"&gt;&lt;font face="Courier New, monospace" id="z5bq1192"&gt;&lt;font id="z5bq1194" size="1"&gt;mov eax, [ss:bp+4]&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1195"&gt;&lt;font face="Courier New, monospace" id="z5bq1196"&gt;&lt;font id="z5bq1198" size="1"&gt;mov cr0, eax&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1199"&gt;&lt;font face="Courier New, monospace" id="z5bq1200"&gt;&lt;font id="z5bq1202" size="1"&gt;pop bp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1203"&gt;&lt;font face="Courier New, monospace" id="z5bq1204"&gt;&lt;font id="z5bq1206" size="1"&gt;retn&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1207"&gt;&lt;br id="z5bq1208"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1209"&gt;&lt;font face="Courier New, monospace" id="z5bq1210"&gt;&lt;font id="z5bq1212" size="1"&gt;_lgdt: ; carga el registro GDTR con el par&amp;aacute;metro&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1213"&gt;&lt;font face="Courier New, monospace" id="z5bq1214"&gt;&lt;font id="z5bq1216" size="1"&gt;push bp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1217"&gt;&lt;font face="Courier New, monospace" id="z5bq1218"&gt;&lt;font id="z5bq1220" size="1"&gt;mov bp, sp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1221"&gt;&lt;font face="Courier New, monospace" id="z5bq1222"&gt;&lt;font id="z5bq1224" size="1"&gt;push bx&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1225"&gt;&lt;font face="Courier New, monospace" id="z5bq1226"&gt;&lt;font id="z5bq1228" size="1"&gt;mov bx, [ss:bp+4]&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1229"&gt;&lt;font face="Courier New, monospace" id="z5bq1230"&gt;&lt;font id="z5bq1232" size="1"&gt;lgdt [ds:bx]&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1233"&gt;&lt;font face="Courier New, monospace" id="z5bq1234"&gt;&lt;font id="z5bq1236" size="1"&gt;pop bx&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1237"&gt;&lt;font face="Courier New, monospace" id="z5bq1238"&gt;&lt;font id="z5bq1240" size="1"&gt;pop bp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1241"&gt;&lt;font face="Courier New, monospace" id="z5bq1242"&gt;&lt;font id="z5bq1244" size="1"&gt;retn&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1245"&gt;&lt;br id="z5bq1246"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1247"&gt;&lt;font face="Courier New, monospace" id="z5bq1248"&gt;&lt;font id="z5bq1250" size="1"&gt;_lidt: ; carga el registro IDTR con el par&amp;aacute;metro&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1251"&gt;&lt;font face="Courier New, monospace" id="z5bq1252"&gt;&lt;font id="z5bq1254" size="1"&gt;push bp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1255"&gt;&lt;font face="Courier New, monospace" id="z5bq1256"&gt;&lt;font id="z5bq1258" size="1"&gt;mov bp, sp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1259"&gt;&lt;font face="Courier New, monospace" id="z5bq1260"&gt;&lt;font id="z5bq1262" size="1"&gt;push bx&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1263"&gt;&lt;font face="Courier New, monospace" id="z5bq1264"&gt;&lt;font id="z5bq1266" size="1"&gt;mov bx, [ss:bp+4]&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1267"&gt;&lt;font face="Courier New, monospace" id="z5bq1268"&gt;&lt;font id="z5bq1270" size="1"&gt;lidt [ds:bx]&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1271"&gt;&lt;font face="Courier New, monospace" id="z5bq1272"&gt;&lt;font id="z5bq1274" size="1"&gt;pop bx&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1275"&gt;&lt;font face="Courier New, monospace" id="z5bq1276"&gt;&lt;font id="z5bq1278" size="1"&gt;pop bp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1279"&gt;&lt;font face="Courier New, monospace" id="z5bq1280"&gt;&lt;font id="z5bq1282" size="1"&gt;retn&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1283"&gt;&lt;br id="z5bq1284"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1285"&gt;&lt;font face="Courier New, monospace" id="z5bq1286"&gt;&lt;font id="z5bq1288" size="1"&gt;_update_cs: ; carga el registro CS con el par&amp;aacute;metro&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1289"&gt;&lt;font face="Courier New, monospace" id="z5bq1290"&gt;&lt;font id="z5bq1292" size="1"&gt;push bp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1293"&gt;&lt;font face="Courier New, monospace" id="z5bq1294"&gt;&lt;font id="z5bq1296" size="1"&gt;mov bp, sp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1297"&gt;&lt;font face="Courier New, monospace" id="z5bq1298"&gt;&lt;font id="z5bq1300" size="1"&gt;mov ax, [ss:bp+4]&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1301"&gt;&lt;font face="Courier New, monospace" id="z5bq1302"&gt;&lt;font id="z5bq1304" size="1"&gt;push ax&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1305"&gt;&lt;font face="Courier New, monospace" id="z5bq1306"&gt;&lt;font id="z5bq1308" size="1"&gt;push word .1&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1309"&gt;&lt;font face="Courier New, monospace" id="z5bq1310"&gt;&lt;font id="z5bq1312" size="1"&gt;retf&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1313"&gt;&lt;font face="Courier New, monospace" id="z5bq1314"&gt;&lt;font id="z5bq1316" size="1"&gt;.1:&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1317"&gt;&lt;font face="Courier New, monospace" id="z5bq1318"&gt;&lt;font id="z5bq1320" size="1"&gt;pop bp&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1321"&gt;&lt;font face="Courier New, monospace" id="z5bq1322"&gt;&lt;font id="z5bq1324" size="1"&gt;retn&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1325"&gt;&lt;br id="z5bq1326"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1327"&gt;&lt;font face="Courier New, monospace" id="z5bq1328"&gt;&lt;font id="z5bq1330" size="1"&gt;_enable: ; pone en 1 el flag IF&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1331"&gt;&lt;font face="Courier New, monospace" id="z5bq1332"&gt;&lt;font id="z5bq1334" size="1"&gt; sti&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1335"&gt;&lt;font face="Courier New, monospace" id="z5bq1336"&gt;&lt;font id="z5bq1338" size="1"&gt; retn&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1339"&gt;&lt;br id="z5bq1340"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1341"&gt;&lt;font face="Courier New, monospace" id="z5bq1342"&gt;&lt;font id="z5bq1344" size="1"&gt;_disable: ; pone en 0 el flag IF&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1345"&gt;&lt;font face="Courier New, monospace" id="z5bq1346"&gt;&lt;font id="z5bq1348" size="1"&gt; cli&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1349"&gt;&lt;font face="Courier New, monospace" id="z5bq1350"&gt;&lt;font id="z5bq1352" size="1"&gt; retn&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1353"&gt;&lt;br id="z5bq1354"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1355"&gt;&lt;font face="Courier New, monospace" id="z5bq1356"&gt;&lt;font id="z5bq1358" size="1"&gt;_timer_isr:&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1359"&gt;&lt;font face="Courier New, monospace" id="z5bq1360"&gt;&lt;font id="z5bq1362" size="1"&gt;pushad ; salva todos los registros de uso general&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1363"&gt;&lt;font face="Courier New, monospace" id="z5bq1364"&gt;&lt;font id="z5bq1366" size="1"&gt;call _timer_handler ; llama a timer_handler()&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1367"&gt;&lt;font face="Courier New, monospace" id="z5bq1368"&gt;&lt;font id="z5bq1370" size="1"&gt;popad ; restaura todos los registros de uso general&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1371"&gt;&lt;font face="Courier New, monospace" id="z5bq1372"&gt;&lt;font id="z5bq1374" size="1"&gt;iretd&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1375"&gt;&lt;br id="z5bq1376"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1377"&gt;&lt;font face="Courier New, monospace" id="z5bq1378"&gt;&lt;font id="z5bq1380" size="1"&gt;_kbd_isr:&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1381"&gt;&lt;font face="Courier New, monospace" id="z5bq1382"&gt;&lt;font id="z5bq1384" size="1"&gt;pushad ; salva todos los registros de uso general&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1385"&gt;&lt;font face="Courier New, monospace" id="z5bq1386"&gt;&lt;font id="z5bq1388" size="1"&gt;call _kbd_handler ; llama a kbd_handler()&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1389"&gt;&lt;font face="Courier New, monospace" id="z5bq1390"&gt;&lt;font id="z5bq1392" size="1"&gt;popad ; restaura todos los registros de uso general&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1393"&gt;&lt;font face="Courier New, monospace" id="z5bq1394"&gt;&lt;font id="z5bq1396" size="1"&gt;iretd&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p class="western" id="z5bq1397"&gt;&lt;br id="z5bq1398"&gt;&lt;/p&gt;&lt;table border="1" bordercolor="#000000" cellpadding="5" cellspacing="0" frame="below" id="z5bq1399" width="600"&gt;&lt;tbody id="z5bq1401"&gt;&lt;tr id="z5bq1402"&gt;&lt;td id="z5bq1403" valign="top" width="590"&gt;&lt;p class="western" id="z5bq1404"&gt; Archivo: ejprog.c &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr id="z5bq1405"&gt;&lt;td id="z5bq1406" valign="top" width="590"&gt;&lt;p class="western" id="z5bq1407"&gt;&lt;font face="Courier New, monospace" id="z5bq1408"&gt;&lt;font id="z5bq1410" size="1"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1411"&gt;&lt;br id="z5bq1412"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1413"&gt;&lt;font face="Courier New, monospace" id="z5bq1414"&gt;&lt;font id="z5bq1416" size="1"&gt;extern unsigned long read_cr0();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1417"&gt;&lt;font face="Courier New, monospace" id="z5bq1418"&gt;&lt;font id="z5bq1420" size="1"&gt;extern void write_cr0(unsigned long);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1421"&gt;&lt;font face="Courier New, monospace" id="z5bq1422"&gt;&lt;font id="z5bq1424" size="1"&gt;extern void lgdt(struct GDTR*);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1425"&gt;&lt;font face="Courier New, monospace" id="z5bq1426"&gt;&lt;font id="z5bq1428" size="1"&gt;extern void lidt(struct IDTR*);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1429"&gt;&lt;font face="Courier New, monospace" id="z5bq1430"&gt;&lt;font id="z5bq1432" size="1"&gt;extern void update_cs(unsigned int);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1433"&gt;&lt;font face="Courier New, monospace" id="z5bq1434"&gt;&lt;font id="z5bq1436" size="1"&gt;extern void enable();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1437"&gt;&lt;font face="Courier New, monospace" id="z5bq1438"&gt;&lt;font id="z5bq1440" size="1"&gt;extern void disable();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1441"&gt;&lt;font face="Courier New, monospace" id="z5bq1442"&gt;&lt;font id="z5bq1444" size="1"&gt;extern interrupt timer_isr();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1445"&gt;&lt;font face="Courier New, monospace" id="z5bq1446"&gt;&lt;font id="z5bq1448" size="1"&gt;extern interrupt kbd_isr();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1449"&gt;&lt;br id="z5bq1450"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1451"&gt;&lt;font face="Courier New, monospace" id="z5bq1452"&gt;&lt;font id="z5bq1454" size="1"&gt;typedef unsigned char byte;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1455"&gt;&lt;font face="Courier New, monospace" id="z5bq1456"&gt;&lt;font id="z5bq1458" size="1"&gt;typedef unsigned int word;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1459"&gt;&lt;font face="Courier New, monospace" id="z5bq1460"&gt;&lt;font id="z5bq1462" size="1"&gt;typedef unsigned long dword;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1463"&gt;&lt;br id="z5bq1464"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1465"&gt;&lt;font face="Courier New, monospace" id="z5bq1466"&gt;&lt;font id="z5bq1468" size="1"&gt;/******************************************************************************/&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1469"&gt;&lt;font face="Courier New, monospace" id="z5bq1470"&gt;&lt;font id="z5bq1472" size="1"&gt;/* Aqu&amp;iacute; se construye la GDT. Esta tabla define los segmentos en modo protegi- */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1473"&gt;&lt;font face="Courier New, monospace" id="z5bq1474"&gt;&lt;font id="z5bq1476" size="1"&gt;/* do. No se dar&amp;aacute;n m&amp;aacute;s detalles en este trabajo, sin embargo es posible en- */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1477"&gt;&lt;font face="Courier New, monospace" id="z5bq1478"&gt;&lt;font id="z5bq1480" size="1"&gt;/* contrar m&amp;aacute;s informaci&amp;oacute;n al respecto en los manuales de INTEL. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1481"&gt;&lt;font face="Courier New, monospace" id="z5bq1482"&gt;&lt;font id="z5bq1484" size="1"&gt;/******************************************************************************/&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1485"&gt;&lt;br id="z5bq1486"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1487"&gt;&lt;font face="Courier New, monospace" id="z5bq1488"&gt;&lt;font id="z5bq1490" size="1"&gt;#define ACS_CODE 0x9A&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1491"&gt;&lt;font face="Courier New, monospace" id="z5bq1492"&gt;&lt;font id="z5bq1494" size="1"&gt;#define ACS_DATA 0x92&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1495"&gt;&lt;font face="Courier New, monospace" id="z5bq1496"&gt;&lt;font id="z5bq1498" size="1"&gt;#define ACS_STACK 0x92&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1499"&gt;&lt;br id="z5bq1500"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1501"&gt;&lt;font face="Courier New, monospace" id="z5bq1502"&gt;&lt;font id="z5bq1504" size="1"&gt;struct DESCR_SEG {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1505"&gt;&lt;font face="Courier New, monospace" id="z5bq1506"&gt;&lt;font id="z5bq1508" size="1"&gt;word limite,&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1509"&gt;&lt;font face="Courier New, monospace" id="z5bq1510"&gt;&lt;font id="z5bq1512" size="1"&gt;base_l;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1513"&gt;&lt;font face="Courier New, monospace" id="z5bq1514"&gt;&lt;font id="z5bq1516" size="1"&gt;byte base_m,&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1517"&gt;&lt;font face="Courier New, monospace" id="z5bq1518"&gt;&lt;font id="z5bq1520" size="1"&gt;acceso,&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1521"&gt;&lt;font face="Courier New, monospace" id="z5bq1522"&gt;&lt;font id="z5bq1524" size="1"&gt;atributos,&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1525"&gt;&lt;font face="Courier New, monospace" id="z5bq1526"&gt;&lt;font id="z5bq1528" size="1"&gt;base_h;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1529"&gt;&lt;font face="Courier New, monospace" id="z5bq1530"&gt;&lt;font id="z5bq1532" size="1"&gt;} gdt[4] = { 0 };&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1533"&gt;&lt;br id="z5bq1534"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1535"&gt;&lt;font face="Courier New, monospace" id="z5bq1536"&gt;&lt;font id="z5bq1538" size="1"&gt;struct GDTR {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1539"&gt;&lt;font face="Courier New, monospace" id="z5bq1540"&gt;&lt;font id="z5bq1542" size="1"&gt;word limite;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1543"&gt;&lt;font face="Courier New, monospace" id="z5bq1544"&gt;&lt;font id="z5bq1546" size="1"&gt;dword base;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1547"&gt;&lt;font face="Courier New, monospace" id="z5bq1548"&gt;&lt;font id="z5bq1550" size="1"&gt;} gdtr;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1551"&gt;&lt;br id="z5bq1552"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1553"&gt;&lt;font face="Courier New, monospace" id="z5bq1554"&gt;&lt;font id="z5bq1556" size="1"&gt;void setup_GDT_entry (struct DESCR_SEG *item,&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1557"&gt;&lt;font face="Courier New, monospace" id="z5bq1558"&gt;&lt;font id="z5bq1560" size="1"&gt;dword base, dword limite, byte acceso) {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1561"&gt;&lt;font face="Courier New, monospace" id="z5bq1562"&gt;&lt;font id="z5bq1564" size="1"&gt;item-&amp;gt;limite = limite;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1565"&gt;&lt;font face="Courier New, monospace" id="z5bq1566"&gt;&lt;font id="z5bq1568" size="1"&gt;item-&amp;gt;base_l = base;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1569"&gt;&lt;font face="Courier New, monospace" id="z5bq1570"&gt;&lt;font id="z5bq1572" size="1"&gt;item-&amp;gt;base_m = base &amp;gt;&amp;gt; 16;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1573"&gt;&lt;font face="Courier New, monospace" id="z5bq1574"&gt;&lt;font id="z5bq1576" size="1"&gt;item-&amp;gt;acceso = acceso;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1577"&gt;&lt;font face="Courier New, monospace" id="z5bq1578"&gt;&lt;font id="z5bq1580" size="1"&gt;}&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1581"&gt;&lt;br id="z5bq1582"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1583"&gt;&lt;font face="Courier New, monospace" id="z5bq1584"&gt;&lt;font id="z5bq1586" size="1"&gt;void setup_GDT() {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1587"&gt;&lt;font face="Courier New, monospace" id="z5bq1588"&gt;&lt;font id="z5bq1590" size="1"&gt;setup_GDT_entry (&amp;amp;gdt[1], ((dword)_CS)&amp;lt;&amp;lt;4, 0xFFFF, ACS_CODE);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1591"&gt;&lt;font face="Courier New, monospace" id="z5bq1592"&gt;&lt;font id="z5bq1594" size="1"&gt;setup_GDT_entry (&amp;amp;gdt[2], ((dword)_DS)&amp;lt;&amp;lt;4, 0xFFFF, ACS_DATA);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1595"&gt;&lt;font face="Courier New, monospace" id="z5bq1596"&gt;&lt;font id="z5bq1598" size="1"&gt;setup_GDT_entry (&amp;amp;gdt[3], ((dword)_SS)&amp;lt;&amp;lt;4, 0xFFFF, ACS_STACK);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1599"&gt;&lt;br id="z5bq1600"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1601"&gt;&lt;font face="Courier New, monospace" id="z5bq1602"&gt;&lt;font id="z5bq1604" size="1"&gt;gdtr.base = ((dword) _DS)&amp;lt;&amp;lt;4;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1605"&gt;&lt;font face="Courier New, monospace" id="z5bq1606"&gt;&lt;font id="z5bq1608" size="1"&gt;gdtr.base += (word) gdt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1609"&gt;&lt;font face="Courier New, monospace" id="z5bq1610"&gt;&lt;font id="z5bq1612" size="1"&gt;gdtr.limite = sizeof(gdt)-1;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1613"&gt;&lt;font face="Courier New, monospace" id="z5bq1614"&gt;&lt;font id="z5bq1616" size="1"&gt;lgdt(&amp;amp;gdtr);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1617"&gt;&lt;font face="Courier New, monospace" id="z5bq1618"&gt;&lt;font id="z5bq1620" size="1"&gt;}&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1621"&gt;&lt;br id="z5bq1622"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1623"&gt;&lt;font face="Courier New, monospace" id="z5bq1624"&gt;&lt;font id="z5bq1626" size="1"&gt;/******************************************************************************/&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1627"&gt;&lt;br id="z5bq1628"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1629"&gt;&lt;font face="Courier New, monospace" id="z5bq1630"&gt;&lt;font id="z5bq1632" size="1"&gt;/* Puertos */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1633"&gt;&lt;font face="Courier New, monospace" id="z5bq1634"&gt;&lt;font id="z5bq1636" size="1"&gt;#define PORT_8259M 0x20&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1637"&gt;&lt;font face="Courier New, monospace" id="z5bq1638"&gt;&lt;font id="z5bq1640" size="1"&gt;#define PORT_8259S 0xA0&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1641"&gt;&lt;font face="Courier New, monospace" id="z5bq1642"&gt;&lt;font id="z5bq1644" size="1"&gt;#define PORT_KBD_A 0x60&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1645"&gt;&lt;br id="z5bq1646"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1647"&gt;&lt;font face="Courier New, monospace" id="z5bq1648"&gt;&lt;font id="z5bq1650" size="1"&gt;/* Palabras para los 8259 */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1651"&gt;&lt;font face="Courier New, monospace" id="z5bq1652"&gt;&lt;font id="z5bq1654" size="1"&gt;#define ICW1 0x11&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1655"&gt;&lt;font face="Courier New, monospace" id="z5bq1656"&gt;&lt;font id="z5bq1658" size="1"&gt;#define ICW3M 0x04&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1659"&gt;&lt;font face="Courier New, monospace" id="z5bq1660"&gt;&lt;font id="z5bq1662" size="1"&gt;#define ICW3S 0x02&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1663"&gt;&lt;font face="Courier New, monospace" id="z5bq1664"&gt;&lt;font id="z5bq1666" size="1"&gt;#define ICW4 0x01&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1667"&gt;&lt;font face="Courier New, monospace" id="z5bq1668"&gt;&lt;font id="z5bq1670" size="1"&gt;#define EOI 0x20&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1671"&gt;&lt;br id="z5bq1672"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1673"&gt;&lt;font face="Courier New, monospace" id="z5bq1674"&gt;&lt;font id="z5bq1676" size="1"&gt;#define INT_GATE_CONFIG 0x8E00&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1677"&gt;&lt;font face="Courier New, monospace" id="z5bq1678"&gt;&lt;font id="z5bq1680" size="1"&gt;#define CODE_SEG_SEL 0x08&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1681"&gt;&lt;br id="z5bq1682"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1683"&gt;&lt;font face="Courier New, monospace" id="z5bq1684"&gt;&lt;font id="z5bq1686" size="1"&gt;/* Estructura de la interrupt-gates. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1687"&gt;&lt;font face="Courier New, monospace" id="z5bq1688"&gt;&lt;font id="z5bq1690" size="1"&gt;struct int_gate {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1691"&gt;&lt;font face="Courier New, monospace" id="z5bq1692"&gt;&lt;font id="z5bq1694" size="1"&gt;word offset_l,&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1695"&gt;&lt;font face="Courier New, monospace" id="z5bq1696"&gt;&lt;font id="z5bq1698" size="1"&gt;segmento,&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1699"&gt;&lt;font face="Courier New, monospace" id="z5bq1700"&gt;&lt;font id="z5bq1702" size="1"&gt;config,&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1703"&gt;&lt;font face="Courier New, monospace" id="z5bq1704"&gt;&lt;font id="z5bq1706" size="1"&gt;offset_h;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1707"&gt;&lt;font face="Courier New, monospace" id="z5bq1708"&gt;&lt;font id="z5bq1710" size="1"&gt;};&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1711"&gt;&lt;br id="z5bq1712"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1713"&gt;&lt;font face="Courier New, monospace" id="z5bq1714"&gt;&lt;font id="z5bq1716" size="1"&gt;/* Estructura del registro IDTR. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1717"&gt;&lt;font face="Courier New, monospace" id="z5bq1718"&gt;&lt;font id="z5bq1720" size="1"&gt;struct IDTR {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1721"&gt;&lt;font face="Courier New, monospace" id="z5bq1722"&gt;&lt;font id="z5bq1724" size="1"&gt;word limite;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1725"&gt;&lt;font face="Courier New, monospace" id="z5bq1726"&gt;&lt;font id="z5bq1728" size="1"&gt;dword base;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1729"&gt;&lt;font face="Courier New, monospace" id="z5bq1730"&gt;&lt;font id="z5bq1732" size="1"&gt;};&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1733"&gt;&lt;br id="z5bq1734"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1735"&gt;&lt;font face="Courier New, monospace" id="z5bq1736"&gt;&lt;font id="z5bq1738" size="1"&gt;struct int_gate idt[0x22] = { 0 }; /* IDT */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1739"&gt;&lt;font face="Courier New, monospace" id="z5bq1740"&gt;&lt;font id="z5bq1742" size="1"&gt;struct IDTR idtr; /* IDTR */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1743"&gt;&lt;font face="Courier New, monospace" id="z5bq1744"&gt;&lt;font id="z5bq1746" size="1"&gt;byte old_IRQ_maskM, old_IRQ_maskS;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1747"&gt;&lt;font face="Courier New, monospace" id="z5bq1748"&gt;&lt;font id="z5bq1750" size="1"&gt;volatile byte scancode=0;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1751"&gt;&lt;font face="Courier New, monospace" id="z5bq1752"&gt;&lt;font id="z5bq1754" size="1"&gt;unsigned int ticks=0;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1755"&gt;&lt;br id="z5bq1756"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1757"&gt;&lt;font face="Courier New, monospace" id="z5bq1758"&gt;&lt;font id="z5bq1760" size="1"&gt;/* Funci&amp;oacute;n llamada por timer_isr(). */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1761"&gt;&lt;font face="Courier New, monospace" id="z5bq1762"&gt;&lt;font id="z5bq1764" size="1"&gt;void timer_handler() {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1765"&gt;&lt;font face="Courier New, monospace" id="z5bq1766"&gt;&lt;font id="z5bq1768" size="1"&gt;/* El BIOS ha configurado el timer para que envie interrupciones a una */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1769"&gt;&lt;font face="Courier New, monospace" id="z5bq1770"&gt;&lt;font id="z5bq1772" size="1"&gt;/* frecuencia de 18,2 Hz, por lo tanto en 20 segundos habra 364 inte- */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1773"&gt;&lt;font face="Courier New, monospace" id="z5bq1774"&gt;&lt;font id="z5bq1776" size="1"&gt;/* rrupciones aproximadamente. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1777"&gt;&lt;font face="Courier New, monospace" id="z5bq1778"&gt;&lt;font id="z5bq1780" size="1"&gt; if (ticks++ == 364) scancode = 0x81;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1781"&gt;&lt;font face="Courier New, monospace" id="z5bq1782"&gt;&lt;font id="z5bq1784" size="1"&gt; outportb (PORT_8259M, EOI);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1785"&gt;&lt;font face="Courier New, monospace" id="z5bq1786"&gt;&lt;font id="z5bq1788" size="1"&gt;}&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1789"&gt;&lt;br id="z5bq1790"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1791"&gt;&lt;font face="Courier New, monospace" id="z5bq1792"&gt;&lt;font id="z5bq1794" size="1"&gt;/* Funci&amp;oacute;n llamada por kbd_isr(). */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1795"&gt;&lt;font face="Courier New, monospace" id="z5bq1796"&gt;&lt;font id="z5bq1798" size="1"&gt;void kbd_handler() {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1799"&gt;&lt;font face="Courier New, monospace" id="z5bq1800"&gt;&lt;font id="z5bq1802" size="1"&gt; /* Leyendo el c&amp;oacute;digo de tecla. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1803"&gt;&lt;font face="Courier New, monospace" id="z5bq1804"&gt;&lt;font id="z5bq1806" size="1"&gt; scancode = inportb (PORT_KBD_A);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1807"&gt;&lt;font face="Courier New, monospace" id="z5bq1808"&gt;&lt;font id="z5bq1810" size="1"&gt; outportb (PORT_8259M, EOI);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1811"&gt;&lt;font face="Courier New, monospace" id="z5bq1812"&gt;&lt;font id="z5bq1814" size="1"&gt;}&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1815"&gt;&lt;br id="z5bq1816"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1817"&gt;&lt;font face="Courier New, monospace" id="z5bq1818"&gt;&lt;font id="z5bq1820" size="1"&gt;void setup_IDT() {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1821"&gt;&lt;font face="Courier New, monospace" id="z5bq1822"&gt;&lt;font id="z5bq1824" size="1"&gt; /* Cargando en la IDT las interrupt-gates para el timer y el teclado. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1825"&gt;&lt;font face="Courier New, monospace" id="z5bq1826"&gt;&lt;font id="z5bq1828" size="1"&gt; idt[0x20].offset_l = (word) &amp;amp;timer_isr;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1829"&gt;&lt;font face="Courier New, monospace" id="z5bq1830"&gt;&lt;font id="z5bq1832" size="1"&gt; idt[0x20].segmento = CODE_SEG_SEL;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1833"&gt;&lt;font face="Courier New, monospace" id="z5bq1834"&gt;&lt;font id="z5bq1836" size="1"&gt; idt[0x20].config = INT_GATE_CONFIG;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1837"&gt;&lt;br id="z5bq1838"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1839"&gt;&lt;font face="Courier New, monospace" id="z5bq1840"&gt;&lt;font id="z5bq1842" size="1"&gt; idt[0x21].offset_l = (word) &amp;amp;kbd_isr;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1843"&gt;&lt;font face="Courier New, monospace" id="z5bq1844"&gt;&lt;font id="z5bq1846" size="1"&gt; idt[0x21].segmento = CODE_SEG_SEL;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1847"&gt;&lt;font face="Courier New, monospace" id="z5bq1848"&gt;&lt;font id="z5bq1850" size="1"&gt; idt[0x21].config = INT_GATE_CONFIG;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1851"&gt;&lt;br id="z5bq1852"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1853"&gt;&lt;font face="Courier New, monospace" id="z5bq1854"&gt;&lt;font id="z5bq1856" size="1"&gt; /* Cargando el registro IDTR. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1857"&gt;&lt;font face="Courier New, monospace" id="z5bq1858"&gt;&lt;font id="z5bq1860" size="1"&gt; idtr.base = ((dword) _DS)&amp;lt;&amp;lt;4;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1861"&gt;&lt;font face="Courier New, monospace" id="z5bq1862"&gt;&lt;font id="z5bq1864" size="1"&gt; idtr.base += (word) idt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1865"&gt;&lt;font face="Courier New, monospace" id="z5bq1866"&gt;&lt;font id="z5bq1868" size="1"&gt; idtr.limite = sizeof(idt)-1;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1869"&gt;&lt;font face="Courier New, monospace" id="z5bq1870"&gt;&lt;font id="z5bq1872" size="1"&gt; lidt(&amp;amp;idtr);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1873"&gt;&lt;font face="Courier New, monospace" id="z5bq1874"&gt;&lt;font id="z5bq1876" size="1"&gt;}&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1877"&gt;&lt;br id="z5bq1878"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1879"&gt;&lt;font face="Courier New, monospace" id="z5bq1880"&gt;&lt;font id="z5bq1882" size="1"&gt;void setup_PIC (byte vector_maestro, byte vector_esclavo) {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1883"&gt;&lt;font face="Courier New, monospace" id="z5bq1884"&gt;&lt;font id="z5bq1886" size="1"&gt; outportb (PORT_8259M, ICW1); /* comienza la inicializaci&amp;oacute;n del 8259 */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1887"&gt;&lt;font face="Courier New, monospace" id="z5bq1888"&gt;&lt;font id="z5bq1890" size="1"&gt; outportb (PORT_8259S, ICW1);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1891"&gt;&lt;font face="Courier New, monospace" id="z5bq1892"&gt;&lt;font id="z5bq1894" size="1"&gt; outportb (PORT_8259M+1,vector_maestro); /* vector base para el maestro */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1895"&gt;&lt;font face="Courier New, monospace" id="z5bq1896"&gt;&lt;font id="z5bq1898" size="1"&gt; outportb (PORT_8259S+1,vector_esclavo); /* vector base para el esclavo */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1899"&gt;&lt;font face="Courier New, monospace" id="z5bq1900"&gt;&lt;font id="z5bq1902" size="1"&gt; outportb (PORT_8259M+1,ICW3M);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1903"&gt;&lt;font face="Courier New, monospace" id="z5bq1904"&gt;&lt;font id="z5bq1906" size="1"&gt; outportb (PORT_8259S+1,ICW3S);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1907"&gt;&lt;font face="Courier New, monospace" id="z5bq1908"&gt;&lt;font id="z5bq1910" size="1"&gt; outportb (PORT_8259M+1,ICW4);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1911"&gt;&lt;font face="Courier New, monospace" id="z5bq1912"&gt;&lt;font id="z5bq1914" size="1"&gt; outportb (PORT_8259S+1,ICW4);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1915"&gt;&lt;font face="Courier New, monospace" id="z5bq1916"&gt;&lt;font id="z5bq1918" size="1"&gt;}&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1919"&gt;&lt;br id="z5bq1920"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1921"&gt;&lt;font face="Courier New, monospace" id="z5bq1922"&gt;&lt;font id="z5bq1924" size="1"&gt;int main() {&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1925"&gt;&lt;font face="Courier New, monospace" id="z5bq1926"&gt;&lt;font id="z5bq1928" size="1"&gt; word old_CS, old_DS, old_SS;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1929"&gt;&lt;br id="z5bq1930"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1931"&gt;&lt;font face="Courier New, monospace" id="z5bq1932"&gt;&lt;font id="z5bq1934" size="1"&gt; printf(&amp;quot;Programa de ejemplo: \&amp;quot;Atendiendo interrupciones\&amp;quot;.\n\n&amp;quot;);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1935"&gt;&lt;font face="Courier New, monospace" id="z5bq1936"&gt;&lt;font id="z5bq1938" size="1"&gt; printf(&amp;quot;Para salir presione ESC o espere 20 segundos.&amp;quot;);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1939"&gt;&lt;br id="z5bq1940"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1941"&gt;&lt;font face="Courier New, monospace" id="z5bq1942"&gt;&lt;font id="z5bq1944" size="1"&gt; /* Construyendo la GDT. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1945"&gt;&lt;font face="Courier New, monospace" id="z5bq1946"&gt;&lt;font id="z5bq1948" size="1"&gt; setup_GDT();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1949"&gt;&lt;br id="z5bq1950"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1951"&gt;&lt;font face="Courier New, monospace" id="z5bq1952"&gt;&lt;font id="z5bq1954" size="1"&gt; /* Enmascarando las interrupciones (flag IF = 0). */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1955"&gt;&lt;font face="Courier New, monospace" id="z5bq1956"&gt;&lt;font id="z5bq1958" size="1"&gt; disable();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1959"&gt;&lt;br id="z5bq1960"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1961"&gt;&lt;font face="Courier New, monospace" id="z5bq1962"&gt;&lt;font id="z5bq1964" size="1"&gt;/* Construyendo la IDT. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1965"&gt;&lt;font face="Courier New, monospace" id="z5bq1966"&gt;&lt;font id="z5bq1968" size="1"&gt; setup_IDT();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1969"&gt;&lt;br id="z5bq1970"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1971"&gt;&lt;font face="Courier New, monospace" id="z5bq1972"&gt;&lt;font id="z5bq1974" size="1"&gt; /* Salvando las m&amp;aacute;scaras IRQ. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1975"&gt;&lt;font face="Courier New, monospace" id="z5bq1976"&gt;&lt;font id="z5bq1978" size="1"&gt; old_IRQ_maskM = inportb (PORT_8259M+1);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1979"&gt;&lt;font face="Courier New, monospace" id="z5bq1980"&gt;&lt;font id="z5bq1982" size="1"&gt; old_IRQ_maskS = inportb (PORT_8259S+1);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1983"&gt;&lt;br id="z5bq1984"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1985"&gt;&lt;font face="Courier New, monospace" id="z5bq1986"&gt;&lt;font id="z5bq1988" size="1"&gt; /* Inicializando el PIC para que los vectores de las IRQ vayan desde el */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1989"&gt;&lt;font face="Courier New, monospace" id="z5bq1990"&gt;&lt;font id="z5bq1992" size="1"&gt; /* 0x20 hasta el 0x2F. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1993"&gt;&lt;font face="Courier New, monospace" id="z5bq1994"&gt;&lt;font id="z5bq1996" size="1"&gt; setup_PIC (0x20, 0x28);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1997"&gt;&lt;br id="z5bq1998"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq1999"&gt;&lt;font face="Courier New, monospace" id="z5bq2000"&gt;&lt;font id="z5bq2002" size="1"&gt; /* Enmascarando todas las interrupciones excepto las del timer y las del */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2003"&gt;&lt;font face="Courier New, monospace" id="z5bq2004"&gt;&lt;font id="z5bq2006" size="1"&gt; /* teclado. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2007"&gt;&lt;font face="Courier New, monospace" id="z5bq2008"&gt;&lt;font id="z5bq2010" size="1"&gt; outportb (PORT_8259M+1, 0xFC);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2011"&gt;&lt;font face="Courier New, monospace" id="z5bq2012"&gt;&lt;font id="z5bq2014" size="1"&gt; outportb (PORT_8259S+1, 0xFF);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2015"&gt;&lt;br id="z5bq2016"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2017"&gt;&lt;font face="Courier New, monospace" id="z5bq2018"&gt;&lt;font id="z5bq2020" size="1"&gt; /* Salvando el contenido de los registros de segmento. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2021"&gt;&lt;font face="Courier New, monospace" id="z5bq2022"&gt;&lt;font id="z5bq2024" size="1"&gt; old_CS = _CS;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2025"&gt;&lt;font face="Courier New, monospace" id="z5bq2026"&gt;&lt;font id="z5bq2028" size="1"&gt; old_DS = _DS;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2029"&gt;&lt;font face="Courier New, monospace" id="z5bq2030"&gt;&lt;font id="z5bq2032" size="1"&gt; old_SS = _SS;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2033"&gt;&lt;br id="z5bq2034"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2035"&gt;&lt;font face="Courier New, monospace" id="z5bq2036"&gt;&lt;font id="z5bq2038" size="1"&gt; /* Pasando a modo protegido. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2039"&gt;&lt;font face="Courier New, monospace" id="z5bq2040"&gt;&lt;font id="z5bq2042" size="1"&gt; write_cr0 (read_cr0() | 1L);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2043"&gt;&lt;br id="z5bq2044"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2045"&gt;&lt;font face="Courier New, monospace" id="z5bq2046"&gt;&lt;font id="z5bq2048" size="1"&gt; /* Cargando los registros de segmento con los valores para el modo pro- */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2049"&gt;&lt;font face="Courier New, monospace" id="z5bq2050"&gt;&lt;font id="z5bq2052" size="1"&gt; /* tegido. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2053"&gt;&lt;font face="Courier New, monospace" id="z5bq2054"&gt;&lt;font id="z5bq2056" size="1"&gt; update_cs (0x08);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2057"&gt;&lt;font face="Courier New, monospace" id="z5bq2058"&gt;&lt;font id="z5bq2060" size="1"&gt; _ES = _DS = 0x10;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2061"&gt;&lt;font face="Courier New, monospace" id="z5bq2062"&gt;&lt;font id="z5bq2064" size="1"&gt; _SS = 0x18;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2065"&gt;&lt;br id="z5bq2066"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2067"&gt;&lt;font face="Courier New, monospace" id="z5bq2068"&gt;&lt;font id="z5bq2070" size="1"&gt; /* IF = 1 */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2071"&gt;&lt;font face="Courier New, monospace" id="z5bq2072"&gt;&lt;font id="z5bq2074" size="1"&gt; enable();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2075"&gt;&lt;br id="z5bq2076"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2077"&gt;&lt;font face="Courier New, monospace" id="z5bq2078"&gt;&lt;font id="z5bq2080" size="1"&gt; /* Esperando por ESC. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2081"&gt;&lt;font face="Courier New, monospace" id="z5bq2082"&gt;&lt;font id="z5bq2084" size="1"&gt; while (scancode!=0x81) {}&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2085"&gt;&lt;br id="z5bq2086"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2087"&gt;&lt;font face="Courier New, monospace" id="z5bq2088"&gt;&lt;font id="z5bq2090" size="1"&gt; /* IF = 0 */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2091"&gt;&lt;font face="Courier New, monospace" id="z5bq2092"&gt;&lt;font id="z5bq2094" size="1"&gt;disable();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2095"&gt;&lt;br id="z5bq2096"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2097"&gt;&lt;font face="Courier New, monospace" id="z5bq2098"&gt;&lt;font id="z5bq2100" size="1"&gt; /* Volviendo a modo real. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2101"&gt;&lt;font face="Courier New, monospace" id="z5bq2102"&gt;&lt;font id="z5bq2104" size="1"&gt; write_cr0 (read_cr0() &amp;amp; 0xFFFFFFFEL);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2105"&gt;&lt;br id="z5bq2106"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2107"&gt;&lt;font face="Courier New, monospace" id="z5bq2108"&gt;&lt;font id="z5bq2110" size="1"&gt; /* Restaurando los registro de segmento. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2111"&gt;&lt;font face="Courier New, monospace" id="z5bq2112"&gt;&lt;font id="z5bq2114" size="1"&gt; update_cs (old_CS);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2115"&gt;&lt;font face="Courier New, monospace" id="z5bq2116"&gt;&lt;font id="z5bq2118" size="1"&gt; _ES = _DS = old_DS;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2119"&gt;&lt;font face="Courier New, monospace" id="z5bq2120"&gt;&lt;font id="z5bq2122" size="1"&gt; _SS = old_SS;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2123"&gt;&lt;br id="z5bq2124"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2125"&gt;&lt;font face="Courier New, monospace" id="z5bq2126"&gt;&lt;font id="z5bq2128" size="1"&gt; /* Restaurando el IDTR. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2129"&gt;&lt;font face="Courier New, monospace" id="z5bq2130"&gt;&lt;font id="z5bq2132" size="1"&gt; idtr.base = 0;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2133"&gt;&lt;font face="Courier New, monospace" id="z5bq2134"&gt;&lt;font id="z5bq2136" size="1"&gt; idtr.limite = 0x3FF;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2137"&gt;&lt;font face="Courier New, monospace" id="z5bq2138"&gt;&lt;font id="z5bq2140" size="1"&gt; lidt (&amp;amp;idtr);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2141"&gt;&lt;br id="z5bq2142"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2143"&gt;&lt;font face="Courier New, monospace" id="z5bq2144"&gt;&lt;font id="z5bq2146" size="1"&gt; /* Inicializando el PIC como estaba antes. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2147"&gt;&lt;font face="Courier New, monospace" id="z5bq2148"&gt;&lt;font id="z5bq2150" size="1"&gt; setup_PIC (0x08, 0x70);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2151"&gt;&lt;br id="z5bq2152"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2153"&gt;&lt;font face="Courier New, monospace" id="z5bq2154"&gt;&lt;font id="z5bq2156" size="1"&gt; /* Restaurando las m&amp;aacute;scaras IRQ. */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2157"&gt;&lt;font face="Courier New, monospace" id="z5bq2158"&gt;&lt;font id="z5bq2160" size="1"&gt; outportb (PORT_8259M+1, old_IRQ_maskM);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2161"&gt;&lt;font face="Courier New, monospace" id="z5bq2162"&gt;&lt;font id="z5bq2164" size="1"&gt; outportb (PORT_8259S+1, old_IRQ_maskS);&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2165"&gt;&lt;br id="z5bq2166"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2167"&gt;&lt;font face="Courier New, monospace" id="z5bq2168"&gt;&lt;font id="z5bq2170" size="1"&gt; /* IF = 1 */&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2171"&gt;&lt;font face="Courier New, monospace" id="z5bq2172"&gt;&lt;font id="z5bq2174" size="1"&gt; enable();&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2175"&gt;&lt;br id="z5bq2176"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2177"&gt;&lt;font face="Courier New, monospace" id="z5bq2178"&gt;&lt;font id="z5bq2180" size="1"&gt; return 0;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2181"&gt;&lt;font face="Courier New, monospace" id="z5bq2182"&gt;&lt;font id="z5bq2184" size="1"&gt;}&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p class="western" id="z5bq2185"&gt;&lt;br id="z5bq2186"&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2187"&gt;&lt;font id="z5bq2188" size="4"&gt;&lt;u&gt;&lt;b&gt;REFERENCIAS&lt;/b&gt;&lt;/u&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="western" id="z5bq2191"&gt;&lt;br id="z5bq2192"&gt;&lt;/p&gt;&lt;ul id="z5bq2193"&gt;&lt;li id="z5bq2194"&gt;&lt;p class="western" id="z5bq2195"&gt; Intel Architecture Software Developer&amp;rsquo;s Manual Volume 1 &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq2196"&gt;&lt;p class="western" id="z5bq2197"&gt; Intel Architecture Software Developer&amp;rsquo;s Manual Volume 3 &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq2198"&gt;&lt;p class="western" id="z5bq2199"&gt; webster.csu.cr.edu &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq2200"&gt;&lt;p class="western" id="z5bq2201"&gt; www.beyondlogic.org &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq2202"&gt;&lt;p class="western" id="z5bq2203"&gt; www.cources.ece.uiuc.edu/ece291/lecture/spring2003 &lt;/p&gt;&lt;/li&gt;&lt;ul id="z5bq2204"&gt;&lt;li id="z5bq2205"&gt;&lt;p class="western" id="z5bq2206"&gt; apuntes de &lt;font color="#808080" id="z5bq2207"&gt;Computer Engineering II, Dr. Zbigniew Kalbarczyk, University of Illinois at Urbana- Champaign&lt;/font&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li id="z5bq2208"&gt;&lt;p class="western" id="z5bq2209"&gt; wiki.cs.uiuc.edu/cs427 &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq2210"&gt;&lt;p class="western" id="z5bq2211"&gt; my.execpc.com/~greezer/osd/intr. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq2212"&gt;&lt;p class="western" id="z5bq2213"&gt; Linux Interrupts: The Basic Concepts, Mika J. J&amp;auml;rvenp&amp;auml;&amp;auml;, University of Helsinki, Department of Computer Science &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq2214"&gt;&lt;p class="western" id="z5bq2215"&gt; The Linux Kernel, Boston University: Signals and Interrupts. &lt;/p&gt;&lt;/li&gt;&lt;li id="z5bq2216"&gt;&lt;p class="western" id="z5bq2217"&gt; rdtb1.suwon.ac.kr &lt;/p&gt;&lt;/li&gt;&lt;ul id="z5bq2218"&gt;&lt;li id="z5bq2219"&gt;&lt;p class="western" id="z5bq2220"&gt; Real-Time &amp;amp; Multimedia Database Lab., The University of Suwon, Choi,Sook-Young&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li id="z5bq2222"&gt;&lt;p class="western" id="z5bq2223"&gt; Guide to 80x86 assembly, Gavin Estey, 1995 &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p id="z5bq2225" style="margin-right:0.25in"&gt;&lt;/p&gt;&lt;p id="z5bq2227"&gt; 1 &lt;/p&gt;&lt;br id="z5bq2228"&gt;&lt;p&gt;&lt;/p&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-2478199089125707181?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/2478199089125707181/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=2478199089125707181' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2478199089125707181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2478199089125707181'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2011/03/las-interrupciones-en-los-procesadores.html' title='Las Interrupciones en los Procesadores 80x86'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-8746533522888933023</id><published>2010-11-22T17:51:00.004-03:00</published><updated>2010-11-22T18:05:07.686-03:00</updated><title type='text'>La "reventa" del software</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_PyuhTLDSZLs/TOrYsRKAUMI/AAAAAAAAAYc/BReUB5RYnU4/s1600/rich-sleep.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 329px; height: 400px;" src="http://2.bp.blogspot.com/_PyuhTLDSZLs/TOrYsRKAUMI/AAAAAAAAAYc/BReUB5RYnU4/s400/rich-sleep.jpg" alt="" id="BLOGGER_PHOTO_ID_5542480546464026818" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Es un pensamiento por ahí al que se llega facilmente, pero se me vino a la cabeza en estos últimos días. Quizás nuevamente, porque ya se me habría aparecido en algún otro momento.&lt;br /&gt;&lt;br /&gt;El software se convierte en un negocio interesante si se consigue desarrollar un vez y vender mil. Y esto no debe tomarse tan literalmente, porque a veces, aunque no vendamos un producto mil veces, podemos reutilizar las ideas (fragmentos de código, si se desea ser más concreto) en otro desarrollo, con lo que estaríamos revendiendo también.&lt;br /&gt;&lt;br /&gt;Desarrollar software es altamente costoso, requiere un gran esfuerzo en aprender tecnologías, entender problemas, desarrollar conceptos, etc, etc, etc. Desarrollar para utilizar o vender pocas veces sencillamente no vale el esfuezo.&lt;br /&gt;&lt;br /&gt;Este concepto no es solamente posible en el software, sino en toda "industria" intelectual, como bien saben los malos columnistas de los &lt;a href="http://www.lanacion.com.ar/nota.asp?nota_id=1327122"&gt;diarios berretas&lt;/a&gt;. Por ejemplo en el arte vemos a los creadores aplicar sus conceptos y repetirse, repetirse y repetirse, hasta que ya no puedan robar más y tengan que sentarse a crear algo nuevo.&lt;br /&gt;&lt;br /&gt;El punto es que el "desarrollar una vez y vender mil" no sólo es una buena idea, sino que es la única viable para que este negocio funcione.&lt;br /&gt;&lt;br /&gt;Es verdad que por ahí estoy descubriendo la pólvora en el siglo XXI, o por ahí ya reutilizaba y revendía pero no me había puesto a darme cuenta... ¡bueno che, soy algo lento!&lt;br /&gt;&lt;br /&gt;Aquí les dejo un interesante artículo sobre la trampa de la reutilización del software:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://techdistrict.kirkk.com/2009/07/08/reuse-is-the-dream-dead/"&gt;http://techdistrict.kirkk.com/2009/07/08/reuse-is-the-dream-dead/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-8746533522888933023?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/8746533522888933023/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=8746533522888933023' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8746533522888933023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8746533522888933023'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/11/la-reventa-del-software.html' title='La &quot;reventa&quot; del software'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_PyuhTLDSZLs/TOrYsRKAUMI/AAAAAAAAAYc/BReUB5RYnU4/s72-c/rich-sleep.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4055682511101608040</id><published>2010-06-19T17:51:00.001-03:00</published><updated>2010-06-19T17:53:37.133-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><title type='text'>Bandera en ASCII</title><content type='html'>&lt;pre&gt;&lt;br /&gt;   o&lt;br /&gt; &lt;___&gt;&lt;br /&gt;  | |______    Argentina&lt;br /&gt;  | |######)        200 años!!!&lt;br /&gt;  | |#####(_________&lt;br /&gt;  | |######|########)&lt;br /&gt;  | |######|#######(_______________ &lt;br /&gt;  | |      |########|##############|&lt;br /&gt;  | |      |########|##############|&lt;br /&gt;  | |      |      __|##############|&lt;br /&gt;  | |      |     /&amp;&amp;|##############|&lt;br /&gt;  | |      |     \&amp;&amp;|              |&lt;br /&gt;  | |######|      ^^|\             |&lt;br /&gt;  | |######|########|/             |&lt;br /&gt;  | |######|########|              |&lt;br /&gt;  | |######|########|##############|&lt;br /&gt;  | |~~~~~~|########|##############|&lt;br /&gt;  | |      '~~~~~~~~|##############|&lt;br /&gt;  | |               |##############|&lt;br /&gt;  | |               '~~~~~~~~~~~~~~'&lt;br /&gt;  | |&lt;br /&gt;  | |&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4055682511101608040?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4055682511101608040/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4055682511101608040' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4055682511101608040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4055682511101608040'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/06/bandera-en-ascii.html' title='Bandera en ASCII'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-5055523278565656521</id><published>2010-06-16T14:10:00.003-03:00</published><updated>2010-06-16T14:15:32.706-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Videojuegos'/><title type='text'>What the Hex?</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://yizzle.com/whatthehex/?n=8"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 259px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/TBkGGGOz68I/AAAAAAAAAWY/p5IqHAqhcSk/s400/what-the-hex.PNG" alt="" id="BLOGGER_PHOTO_ID_5483420723122006978" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;¡Adiviná el color!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-5055523278565656521?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/5055523278565656521/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=5055523278565656521' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5055523278565656521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5055523278565656521'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/06/what-hex.html' title='What the Hex?'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PyuhTLDSZLs/TBkGGGOz68I/AAAAAAAAAWY/p5IqHAqhcSk/s72-c/what-the-hex.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-8760052615724832709</id><published>2010-06-11T15:13:00.004-03:00</published><updated>2010-06-11T15:21:43.354-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Reflexión y Opinión'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>No sé lo que quiero bajar, pero lo quiero ya</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/TBJ9VYoREuI/AAAAAAAAAWA/7k-R_VqZTiw/s1600/rapidshare.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 298px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/TBJ9VYoREuI/AAAAAAAAAWA/7k-R_VqZTiw/s400/rapidshare.jpg" alt="" id="BLOGGER_PHOTO_ID_5481581502805381858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Fuente: &lt;a href="http://notevayasestupida.blogspot.com/2010/06/no-se-lo-que-quiero-bajar-pero-lo.html"&gt;No te vayas, estúpida&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Un signo de los tiempos, en este caso un signo de cómo andarán los  niveles de ansiedad humana, es que los sitios de descargas en Internet,  para no cobrarte, te amenazan con... 90 segundos de espera. Tremendo. Si  pagás es ya, sin demora. Si no pagás, tenés que esperar... un minuto y  medio. Ugh. Solo ciertos monjes zen (los más avanzados) logran superar  esto y por tanto no estarían suscriptos a Rapidshare y seguirían bajando  con semejantes demoras, allá en sus confortables chozas del Himalaya.&lt;br /&gt;&lt;br /&gt;Sí, está bien, ahí dice que, además, lo que gratismente baja en media  hora, garpando baja en tres minutos. ¿Y? Es media hora, andá a mirar ese  pavo a las trufas que tenés al horno que no se te pase, y cuando volvés  ya lo tenés igual, Dios mío, qué carajo nos pasa?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-8760052615724832709?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/8760052615724832709/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=8760052615724832709' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8760052615724832709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8760052615724832709'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/06/no-se-lo-que-quiero-bajar-pero-lo.html' title='No sé lo que quiero bajar, pero lo quiero ya'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PyuhTLDSZLs/TBJ9VYoREuI/AAAAAAAAAWA/7k-R_VqZTiw/s72-c/rapidshare.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4341860781384374720</id><published>2010-04-01T18:38:00.003-03:00</published><updated>2010-04-01T18:49:05.890-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Seguridad'/><title type='text'>Bases de datos, passwords, seguridad y otras yerbas</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PyuhTLDSZLs/S7UUVgrm0jI/AAAAAAAAAM0/Z07sA5IKtCk/s1600/password+security_learnsomuch.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 369px; height: 268px;" src="http://4.bp.blogspot.com/_PyuhTLDSZLs/S7UUVgrm0jI/AAAAAAAAAM0/Z07sA5IKtCk/s400/password+security_learnsomuch.jpg" alt="" id="BLOGGER_PHOTO_ID_5455288883411866162" border="0" /&gt;&lt;/a&gt;&lt;p class="postinfo"&gt;&lt;span class="upper"&gt;Fuente: &lt;a href="http://blog.cuerty.com/2010/03/24/bases-de-datos-passwords-seguridad-y-otras-yerbas/"&gt;Angel Freire Diario de un Programador&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="postinfo"&gt;&lt;span class="upper"&gt;Mar 24, 2010&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;Hoy por la madrugada paso algo bastante fuerte: &lt;a href="http://www.uberbin.net/archivos/seguridad/geelbe-hackeado-y-el-problema-de-las-claves-unicas.php"&gt;hackearon&lt;/a&gt; &lt;a href="http://www.geelbe.com/"&gt;geelbe.com&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Para los que no lo saben geelbe es un “club privado de compras”, un modelo distinto a sitios como Mercado Libre o De Remate donde cualquiera puede participar. La idea es lograr tener una red de confianza entre la gente que participa ya que solamente se entra por invitación.&lt;/p&gt; &lt;p&gt;Al margen de como funciona el sitio, esta madrugada se publico en Internet una lista de usuarios con su respectivo password. ¿Como es esto posible? Facil, los passwords estaban guardados en la base de datos en texto plano.&lt;/p&gt; &lt;p&gt;Existen varias formas en las que uno puede elegir guardar el password de sus usuarios en la base de datos, a saber: &lt;em&gt;en texto plano, encriptadas, encriptadas con salt&lt;/em&gt;. Cada una tiene sus pro y sus contras, y de hecho dependiendo del tipo de aplicación que estemos desarrollando existen leyes al respecto.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Texto plano&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Guardar las claves en texto plano es lo mas simple. Uno tiene registro del password de cada usuario y cuando este intenta ingresar al sistema se compara el password que nos provee contra el que tenemos en la base de datos, si es igual, lo dejamos pasar, si no es igual, impedimos que acceda.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Encriptada&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Cuando uno encripta passwords utiliza algún tipo de hash, esto es, un algoritmo que da por resultado una cadena de texto que no se puede revertir al dato que se ingreso originalmente (el password).&lt;/p&gt; &lt;p&gt;Ejemplos de estos algoritmos son md5 y sha1, los mas utilizados en las aplicaciones WEB por cierto.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Encriptada con salt&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Para entender la encriptacion con salt primero hay que ver una gran falencia en la encriptacion a secas: Si uno asume que su aplicación puede, por alguna falla de seguridad, llegar a dejar expuesta la base de datos, y por consiguiente tener acceso a los passwords encriptados, estos pueden llegar a ser revertidos.&lt;/p&gt; &lt;p&gt;¿Pero como? Si recién dije que se utilizan algoritmos por los cuales no se puede llegar al password partiendo del resultado del algoritmo, bien, existen lo que se conoce como rainbow tables, que son listas de los passwords ya encriptados y su correspondiente password en texto plano. De esta forma cuando uno tiene un password encriptado, puede ir a una rainbow table pre generada con millones de passwords y ver si lo encuentra ahí, de ser así, tiene la versión en texto plano del mismo. Obviamente también existe la “fuerza bruta”, esto es, teniendo el hash empezar a probar encriptar todas las combinaciones de letras, números, etc hasta llegar a algún hash que coincida, y ahí obtenemos el password original (o también se puede utilizar una lista de los passwords mas comunes para probar).&lt;/p&gt; &lt;p&gt;¿Como evitamos que alguien venga y compruebe los passwords guardados en la base de datos contra una rainbow table y obtenga el password original? Bueno, podemos, en lugar de guardar el hash del password, agregarle una pequeña cadena de texto “random” al password original, y después guardarnos el hash resultante de encriptar eso y también guardarnos la cadena. Esta es la practica mas extendida hoy en día y frameworks como Django ya lo hacen desde el vamos, también el cookbook de Ruby on Rails nos recomienda hacerlo. Es mucho menos probable que existan rainbow con el password mas una cadena al azar de que si existen rainbow tables con el password solamente.&lt;/p&gt; &lt;p&gt;Viendo estas tres opciones tenemos que decir que el caso de Geelbe coincida con el primero, ellos no encriptan los passwords guardados en la base de datos lo cual no seria problema si nadie pudiera acceder a la base de datos.&lt;/p&gt; &lt;p&gt;Puedo asumir que como quien tuvo acceso a los passwords los publico en la web, que no accedio al servidor, ya que su intencion era la de hacer algun daño a la imagen de Geelbe y de haber tenido acceso al servidor seguramente hubiera defaceado (ie: cambiado la pagina por algo tipo “hackeado por pepito”) y no solamente publicado los passwords. Seguramente el acceso se dio por algún SQL Injection como &lt;a href="http://www.patriciomolina.com/2010/02/xss-y-sql-injection-en-infobae-com/"&gt;el que Patricio descubrió hace unas semanas en Infobae&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Otro detalle a tener en cuenta, y esta practica no esta tan extendida, es la elección del algoritmo para encriptar/hashear los passwords. Si bien las practicas comunes nos dicen que usemos md5 y sha1, lo cierto es que esos algoritmos no fueron diseñados para esa tarea, son efectivos, si, pero tienen un problema: son rápidos.&lt;/p&gt; &lt;p&gt;¿Que tiene de malo que sean rápidos? Cuando uno controla a un usuario que accede a su sitio por lo general guarda una cookie que. Esta cookie guarda solamente un identificador de sesión el cual en el servidor terminamos asociando con el usuario, esto quiere decir que solamente la primer ves que accede el usuario al sitio se comprueba su password. Así que no necesitamos que sea rápido. ¿Donde si es útil la velocidad del algoritmo de hasheo? Cuando uno trata de hacer brute force. Si vos tenes un hash y queres ir probando todas las palabras posibles contra ese hash, y cada intento te toma milésimas de segundo, vas a llegar mucho mas rápido a destino que si te toma 1 segundo cada intento. Es por eso que es recomendable utilizar algún algoritmo como &lt;a href="http://codahale.com/how-to-safely-store-a-password/"&gt;bcrypt&lt;/a&gt; que si están diseñados para guardar passwords de usuarios (¡Es lento apropósito!).&lt;/p&gt; &lt;p&gt;Si la aplicación por otro lado tiene que manejar datos como tarjetas de crédito y cobros (PayPal, Google checkout, etc), recomiendo leer las guiás de PCI y los blogs de la gente que desarrolla los estándares de seguridad para ese tipo de aplicaciones (por suerte hasta ahora no me toco desarrollar ninguna así de critica).&lt;/p&gt; &lt;p&gt;Una nota al margen del objetivo del post (concientizar del sano storage de passwords): La gente de Geelbe esta haciendo un laburo groso, un SQL Injection no es un bug tan raro y el error grave que tuvieron (tener los passwords en pseudo texto plano) es corregible 100%, no seamos botones y pasemos la lista de usuarios afectados y sus passwords por ahí.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4341860781384374720?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4341860781384374720/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4341860781384374720' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4341860781384374720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4341860781384374720'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/04/bases-de-datos-passwords-seguridad-y.html' title='Bases de datos, passwords, seguridad y otras yerbas'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_PyuhTLDSZLs/S7UUVgrm0jI/AAAAAAAAAM0/Z07sA5IKtCk/s72-c/password+security_learnsomuch.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-2997487905481676227</id><published>2010-03-22T15:52:00.003-03:00</published><updated>2010-03-22T16:02:13.409-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>¿No sabe qué nombre ponerle a sus clases?</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.classnamer.com/"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 294px;" src="http://1.bp.blogspot.com/_PyuhTLDSZLs/S6e9-vmlo4I/AAAAAAAAALg/dWB7bbnxUhs/s400/classnamer.PNG" alt="" id="BLOGGER_PHOTO_ID_5451534759583130498" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-2997487905481676227?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/2997487905481676227/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=2997487905481676227' title='2 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2997487905481676227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2997487905481676227'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/03/no-sabe-que-nombre-ponerle-sus-clases.html' title='¿No sabe qué nombre ponerle a sus clases?'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_PyuhTLDSZLs/S6e9-vmlo4I/AAAAAAAAALg/dWB7bbnxUhs/s72-c/classnamer.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-8542749478457707686</id><published>2010-03-15T18:42:00.000-03:00</published><updated>2010-03-15T18:43:56.400-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Los verdaderos programadores</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_PyuhTLDSZLs/S56p8JYAx7I/AAAAAAAAALU/XfgMQ_I-EcI/s1600-h/programador-binario.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 400px;" src="http://1.bp.blogspot.com/_PyuhTLDSZLs/S56p8JYAx7I/AAAAAAAAALU/XfgMQ_I-EcI/s400/programador-binario.jpg" alt="" id="BLOGGER_PHOTO_ID_5448979449938757554" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-8542749478457707686?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/8542749478457707686/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=8542749478457707686' title='3 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8542749478457707686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8542749478457707686'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/03/los-verdaderos-programadores.html' title='Los verdaderos programadores'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_PyuhTLDSZLs/S56p8JYAx7I/AAAAAAAAALU/XfgMQ_I-EcI/s72-c/programador-binario.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-116851811595589064</id><published>2010-03-11T01:26:00.006-03:00</published><updated>2010-03-11T02:01:01.490-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Reflexión y Opinión'/><title type='text'>Iterando strings en Java</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PyuhTLDSZLs/S5h2w3ve6vI/AAAAAAAAAKw/QPjUJGIPlyE/s1600-h/java-sucks.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 285px; height: 285px;" src="http://4.bp.blogspot.com/_PyuhTLDSZLs/S5h2w3ve6vI/AAAAAAAAAKw/QPjUJGIPlyE/s400/java-sucks.jpg" alt="" id="BLOGGER_PHOTO_ID_5447234331273521906" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;CharacterIterator it = new StringCharacterIterator(&lt;span class="exd_v"&gt;"abcd"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;for (char ch=it.first(); ch != CharacterIterator.DONE; ch=it.next())&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;O sea, Iterator tiene como subclase a CharacterIterator, pero a su vez CharacterIterator tiene como subclase a StringCharacterIterator. Glorioso, 130 caracteres de pura m...agia que hacen cosas tan dificiles como... ¿iterar sobre una cadena?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;En otros lenguajes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;C&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;for (char *c = string; *c != NULL; c++)&lt;br /&gt;/* hacer algo con *c */  &lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Python&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;for c in string:&lt;br /&gt;# hacer algo con c&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-116851811595589064?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/116851811595589064/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=116851811595589064' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/116851811595589064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/116851811595589064'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/03/iterando-strings-en-java.html' title='Iterando strings en Java'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_PyuhTLDSZLs/S5h2w3ve6vI/AAAAAAAAAKw/QPjUJGIPlyE/s72-c/java-sucks.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-240795362833456117</id><published>2010-02-16T01:42:00.004-03:00</published><updated>2010-02-16T02:05:28.942-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><category scheme='http://www.blogger.com/atom/ns#' term='Reflexión y Opinión'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Los lenguajes de verdad vs Java</title><content type='html'>(Por el regreso de &lt;a href="http://es.wikipedia.org/wiki/Brainfuck"&gt;Brainfuck&lt;/a&gt;)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/S3okxjlo67I/AAAAAAAAAKM/k1txNv2iydk/s1600-h/piensa_en_java.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 275px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/S3okxjlo67I/AAAAAAAAAKM/k1txNv2iydk/s400/piensa_en_java.JPG" alt="" id="BLOGGER_PHOTO_ID_5438699933788597170" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;pre&gt;def load():&lt;br /&gt; global a&lt;br /&gt; a = {}&lt;br /&gt; with open("mapa") as f:&lt;br /&gt;     for i, l in enumerate(f):&lt;br /&gt;         for j, c in enumerate(l):&lt;br /&gt;             a[(j,i)] = c&lt;br /&gt;&lt;br /&gt;load()&lt;br /&gt;&lt;br /&gt;for k, v in a.iteritems():&lt;br /&gt; print k, "=", v&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Acababa de escribir estas líneas en Python, lenguaje que no acostumbro a utilizar en mi trabajo habitual donde casi todo se hace con Java, para abrir un archivo de texto, leer los caracteres y colocarlos en un diccionario.&lt;br /&gt;&lt;br /&gt;Mientras, recordaba cómo se hacía para abrir un archivo de texto en Java y leerlo, y &lt;a href="http://www.javapractices.com/topic/TopicAction.do?Id=42"&gt;encontraba por ahí&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="keyword"&gt;import&lt;/span&gt; java.io.*;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; ReadWriteTextFile {&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;/**&lt;br /&gt;* Fetch the entire contents of a text file, and return it in a String.&lt;br /&gt;* This style of implementation does not throw Exceptions to the caller.&lt;br /&gt;*&lt;br /&gt;* @param aFile is a file which already exists and can be read.&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;public&lt;/span&gt; String getContents(File aFile) {&lt;br /&gt;&lt;span class="comment"&gt;//...checks on aFile are elided&lt;br /&gt;&lt;/span&gt;    StringBuilder contents = &lt;span class="keyword"&gt;new&lt;/span&gt; StringBuilder();&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;try&lt;/span&gt; {&lt;br /&gt;  &lt;span class="comment"&gt;//use buffering, reading one line at a time&lt;br /&gt;&lt;/span&gt;      &lt;span class="comment"&gt;//FileReader always assumes default encoding is OK!&lt;br /&gt;&lt;/span&gt;      BufferedReader input =  &lt;span class="keyword"&gt;new&lt;/span&gt; BufferedReader(&lt;span class="keyword"&gt;new&lt;/span&gt; FileReader(aFile));&lt;br /&gt;  &lt;span class="keyword"&gt;try&lt;/span&gt; {&lt;br /&gt;    String line = &lt;span class="keyword"&gt;null&lt;/span&gt;; &lt;span class="comment"&gt;//not declared within while loop&lt;br /&gt;&lt;/span&gt;        &lt;span class="comment"&gt;/*&lt;br /&gt;    * readLine is a bit quirky :&lt;br /&gt;    * it returns the content of a line MINUS the newline.&lt;br /&gt;    * it returns null only for the END of the stream.&lt;br /&gt;    * it returns an empty String if two newlines appear in a row.&lt;br /&gt;    */&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;while&lt;/span&gt; (( line = input.readLine()) != &lt;span class="keyword"&gt;null&lt;/span&gt;){&lt;br /&gt;      contents.append(line);&lt;br /&gt;      contents.append(System.getProperty(&lt;span class="literal"&gt;"line.separator"&lt;/span&gt;));&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;span class="keyword"&gt;finally&lt;/span&gt; {&lt;br /&gt;    input.close();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;span class="keyword"&gt;catch&lt;/span&gt; (IOException ex){&lt;br /&gt;  ex.printStackTrace();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;return&lt;/span&gt; contents.toString();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;/**&lt;br /&gt;* Change the contents of text file in its entirety, overwriting any&lt;br /&gt;* existing text.&lt;br /&gt;*&lt;br /&gt;* This style of implementation throws all exceptions to the caller.&lt;br /&gt;*&lt;br /&gt;* @param aFile is an existing file which can be written to.&lt;br /&gt;* @throws IllegalArgumentException if param does not comply.&lt;br /&gt;* @throws FileNotFoundException if the file does not exist.&lt;br /&gt;* @throws IOException if problem encountered during write.&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;void&lt;/span&gt; setContents(File aFile, String aContents)&lt;br /&gt;                             &lt;span class="keyword"&gt;throws&lt;/span&gt; FileNotFoundException, IOException {&lt;br /&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; (aFile == &lt;span class="keyword"&gt;null&lt;/span&gt;) {&lt;br /&gt;  &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; IllegalArgumentException(&lt;span class="literal"&gt;"File should not be null."&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; (!aFile.exists()) {&lt;br /&gt;  &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; FileNotFoundException (&lt;span class="literal"&gt;"File does not exist: "&lt;/span&gt; + aFile);&lt;br /&gt;}&lt;br /&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; (!aFile.isFile()) {&lt;br /&gt;  &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; IllegalArgumentException(&lt;span class="literal"&gt;"Should not be a directory: "&lt;/span&gt; + aFile);&lt;br /&gt;}&lt;br /&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; (!aFile.canWrite()) {&lt;br /&gt;  &lt;span class="keyword"&gt;throw&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; IllegalArgumentException(&lt;span class="literal"&gt;"File cannot be written: "&lt;/span&gt; + aFile);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;//use buffering&lt;br /&gt;&lt;/span&gt;    Writer output = &lt;span class="keyword"&gt;new&lt;/span&gt; BufferedWriter(&lt;span class="keyword"&gt;new&lt;/span&gt; FileWriter(aFile));&lt;br /&gt;&lt;span class="keyword"&gt;try&lt;/span&gt; {&lt;br /&gt;  &lt;span class="comment"&gt;//FileWriter always assumes default encoding is OK!&lt;br /&gt;&lt;/span&gt;      output.write( aContents );&lt;br /&gt;}&lt;br /&gt;&lt;span class="keyword"&gt;finally&lt;/span&gt; {&lt;br /&gt;  output.close();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;/** Simple test harness.   */&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;public&lt;/span&gt; &lt;span class="keyword"&gt;static&lt;/span&gt; &lt;span class="keyword"&gt;void&lt;/span&gt; main (String... aArguments) &lt;span class="keyword"&gt;throws&lt;/span&gt; IOException {&lt;br /&gt;File testFile = &lt;span class="keyword"&gt;new&lt;/span&gt; File(&lt;span class="literal"&gt;"C:\\Temp\\blah.txt"&lt;/span&gt;);&lt;br /&gt;System.out.println(&lt;span class="literal"&gt;"Original file contents: "&lt;/span&gt; + getContents(testFile));&lt;br /&gt;setContents(testFile, &lt;span class="literal"&gt;"The content of this file has been overwritten..."&lt;/span&gt;);&lt;br /&gt;System.out.println(&lt;span class="literal"&gt;"New file contents: "&lt;/span&gt; + getContents(testFile));&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-240795362833456117?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/240795362833456117/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=240795362833456117' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/240795362833456117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/240795362833456117'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/02/los-lenguajes-de-verdad-vs-java.html' title='Los lenguajes de verdad vs Java'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PyuhTLDSZLs/S3okxjlo67I/AAAAAAAAAKM/k1txNv2iydk/s72-c/piensa_en_java.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-9152526237727035182</id><published>2010-02-12T15:45:00.001-03:00</published><updated>2010-02-12T15:47:33.260-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Mi equipo de programadores</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PyuhTLDSZLs/S3Wh4onCB9I/AAAAAAAAAKE/lE1-lrU3vkE/s1600-h/monkey-tripulacion.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 248px;" src="http://4.bp.blogspot.com/_PyuhTLDSZLs/S3Wh4onCB9I/AAAAAAAAAKE/lE1-lrU3vkE/s400/monkey-tripulacion.jpg" alt="" id="BLOGGER_PHOTO_ID_5437430119465617362" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-9152526237727035182?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/9152526237727035182/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=9152526237727035182' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/9152526237727035182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/9152526237727035182'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2010/02/mi-equipo-de-programadores.html' title='Mi equipo de programadores'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_PyuhTLDSZLs/S3Wh4onCB9I/AAAAAAAAAKE/lE1-lrU3vkE/s72-c/monkey-tripulacion.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4164698561859348567</id><published>2009-12-28T16:35:00.002-03:00</published><updated>2009-12-28T16:40:46.245-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lenguaje C'/><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><title type='text'>La tierra de c++</title><content type='html'>&lt;a href="http://3.bp.blogspot.com/_VUQ3DQEhjsM/SiahYNe6RTI/AAAAAAAAAW0/_5rAQs-31kM/s1600-h/cpplands.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5343135445229913394" border="0" alt="" src="http://3.bp.blogspot.com/_VUQ3DQEhjsM/SiahYNe6RTI/AAAAAAAAAW0/_5rAQs-31kM/s400/cpplands.png" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 279px;"/&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4164698561859348567?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4164698561859348567/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4164698561859348567' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4164698561859348567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4164698561859348567'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/12/la-tierra-de-c.html' title='La tierra de c++'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_VUQ3DQEhjsM/SiahYNe6RTI/AAAAAAAAAW0/_5rAQs-31kM/s72-c/cpplands.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4889729391600714655</id><published>2009-12-11T08:00:00.000-03:00</published><updated>2009-12-11T08:00:05.184-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Análisis y Diseño'/><title type='text'>Porqué importa el software terminado</title><content type='html'>Fuente: &lt;a href="http://www.dosideas.com/metodologias/786-porque-importa-el-software-terminado.html"&gt;Dos Ideas&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;table class="contentpaneopen"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;span class="small"&gt;Escrito por Leonardo De Seta  &lt;/span&gt;       &lt;/td&gt; &lt;/tr&gt;  &lt;tr&gt;  &lt;td class="createdate" valign="top"&gt;   Domingo 06 de Diciembre de 2009 13:38 &lt;/td&gt; &lt;/tr&gt;   &lt;tr&gt; &lt;td valign="top"&gt; &lt;p&gt;&lt;img src="http://www.dosideas.com/images/stories/metodologias/boton-de-play.png" alt="Boton de play" align="left" width="128" height="128" hspace="10" /&gt;Es bien sabido que en Scrum es muy importante tener software que funcione al final de cada sprint. Pero... ¿por qué? Joe Little comparte 4 buenas razones por las cuales tenemos que enfocarnos en tener software que funciona, siempre. &lt;/p&gt; &lt;ol&gt;&lt;li&gt;&lt;strong&gt;Las malas noticias no mejoran con el tiempo&lt;/strong&gt;. Dicho de otra manera, es más barato arreglar un bug ahora que arreglarlo más tarde. O la arquitectura, o el diseño. Tiene que estar terminado.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Lo reconozco cuando lo veo&lt;/strong&gt;. Los usuarios no pueden dar feedback sin algo concreto que mirar. Por lo que "terminado" también significa eso. Tiene que ser los suficientemente concreto para permitir el feedback (y si, a menudo eso son más malas noticias, antes).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;No está terminado hasta que está terminado&lt;/strong&gt;. Y vaya si habremos vivido esta pesadilla. Sólo si está terminado vamos a tener una idea de nuestro progreso real. Y de ahí podremos saber cuándo haremos la entrega.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;No construir sobre una mala base&lt;/strong&gt;. No queremos construir software nuevo por encima de software con errores. Si cambiamos algo abajo, la casa entera se nos podría caer. Nuevamente, ningún bug debe escapar al sprint.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Seguramente a ustedes se les ocurren más motivos por los cuales debemos tener software funcionando, siempre.&lt;/p&gt; &lt;p&gt;Estos son algunos de los motivos por los cuales la &lt;a href="http://www.dosideas.com/wiki/Definicion_De_Terminado"&gt;Definición de Terminado&lt;/a&gt; es un artefacto esencial dentro de Scrum.&lt;/p&gt; &lt;h5&gt;Traducido de &lt;a href="http://agileconsortium.blogspot.com/2009/12/why-working-sw-is-important.html?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+blogspot%2FCdKs+%28Agile+%26+Business%29&amp;amp;utm_content=Google+Reader"&gt;Why working software is important, por Joe Little&lt;/a&gt;.&lt;/h5&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4889729391600714655?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4889729391600714655/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4889729391600714655' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4889729391600714655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4889729391600714655'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/12/porque-importa-el-software-terminado.html' title='Porqué importa el software terminado'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-2993557364638490463</id><published>2009-12-08T23:38:00.006-03:00</published><updated>2009-12-09T00:01:51.498-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algoritmos'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Fusionando secuencias ordenedas con Python</title><content type='html'>Este artículo explica la receta &lt;a href="http://code.activestate.com/recipes/491285" target="_blank"&gt;“Iterator Merge”&lt;/a&gt; (Iterador Fusión) escrita por Raymond Hettinger.&lt;br /&gt;&lt;br /&gt;El objetivo de la misma es devolver una secuencia ordenada de ítems,&lt;br /&gt;fusionando secuencias previamente ordenadas.&lt;br /&gt;&lt;br /&gt;El algoritmo hace uso del módulo estándard &lt;a href="http://docs.python.org/library/heapq.html" target="_blank"&gt;heapq&lt;/a&gt;, el cual implementa una versión particular del algoritmo de &lt;a href="http://en.wikipedia.org/wiki/Priority_queue" target="_blank"&gt;cola de prioridad&lt;/a&gt;. A continuación se muestra el código completo de la receta y luego su explicación:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;1&lt;br /&gt;2&lt;br /&gt;3&lt;br /&gt;4&lt;br /&gt;5&lt;br /&gt;6&lt;br /&gt;7&lt;br /&gt;8&lt;br /&gt;9&lt;br /&gt;10&lt;br /&gt;11&lt;br /&gt;12&lt;br /&gt;13&lt;br /&gt;14&lt;br /&gt;15&lt;br /&gt;16&lt;br /&gt;17&lt;br /&gt;18&lt;br /&gt;19&lt;br /&gt;20&lt;br /&gt;21&lt;br /&gt;22&lt;br /&gt;23&lt;br /&gt;24&lt;br /&gt;25&lt;br /&gt;26&lt;br /&gt;27&lt;br /&gt;28&lt;br /&gt;29&lt;br /&gt;30&lt;br /&gt;31&lt;br /&gt;32&lt;br /&gt;33&lt;br /&gt;34&lt;/pre&gt;&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;pre&gt;import heapq&lt;br /&gt;&lt;br /&gt;def imerge(*iterables):&lt;br /&gt;   &amp;#39;&amp;#39;&amp;#39;Merge multiple sorted inputs into a single sorted output.&lt;br /&gt;&lt;br /&gt;   Equivalent to:  sorted(itertools.chain(*iterables))&lt;br /&gt;&lt;br /&gt;   &amp;gt;&amp;gt;&amp;gt; list(imerge([1,3,5,7], [0,2,4,8], [5,10,15,20], [], [25]))&lt;br /&gt;   [0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25]&lt;br /&gt;&lt;br /&gt;   &amp;#39;&amp;#39;&amp;#39;&lt;br /&gt;   heappop, siftup, _StopIteration = heapq.heappop, heapq._siftup, StopIteration&lt;br /&gt;  &lt;br /&gt;   h = []&lt;br /&gt;   h_append = h.append&lt;br /&gt;   for it in map(iter, iterables):&lt;br /&gt;       try:&lt;br /&gt;           next = it.next&lt;br /&gt;           h_append([next(), next])&lt;br /&gt;       except _StopIteration:&lt;br /&gt;           pass&lt;br /&gt;   heapq.heapify(h)&lt;br /&gt;&lt;br /&gt;   while 1:&lt;br /&gt;       try:&lt;br /&gt;           while 1:&lt;br /&gt;               v, next = s = h[0]      # raises IndexError when h is empty&lt;br /&gt;               yield v&lt;br /&gt;               s[0] = next()           # raises StopIteration when exhausted&lt;br /&gt;               siftup(h, 0)            # restore heap condition&lt;br /&gt;       except _StopIteration:&lt;br /&gt;           heappop(h)                  # remove empty iterator&lt;br /&gt;       except IndexError:&lt;br /&gt;           return&lt;/pre&gt;&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Línea 12&lt;/span&gt;: Se asignan atributos y nombres globales a variables locales, lo que acelera el acceso en la implementación estándard de Python (CPython)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Líneas 14 a 21&lt;/span&gt;: Se genera una lista con los primeros ítems y la función que devuelve el siguiente para cada una de las secuencias. La lista tendrá tantos ítems como secuencias se hayan pasado a la función.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Línea 22&lt;/span&gt;: Se transforma la lista en un montículo (heap) dejándola preparada para realizar las operaciones de la cola de prioridad.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Líneas 24 a 34&lt;/span&gt;: Se obtiene el primer item en la cola, se devuelve su valor y se reemplaza con el siguiente de la secuencia a la que pertenece el ítem devuelto (luego se recalculan las posiciones con siftup). En caso que no haya siguiente en esa secuencia, se elimina de la cola (heappop). La cola va quedando con el ítem y la función que devuelve el siguiente para las secuencias que no se agotaron. El algoritmo termina cuando la cola queda vacía.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Usos del algoritmo&lt;/span&gt;&lt;br /&gt;&lt;p&gt;El algoritmo es eficiente en la utilización de memoria, necesita mantener el menor ítem de cada secuencia y uno más al momento de reemplazarlo por el siguiente, lo que lo hace ideal para fusionar varios archivos con muchos ítems como para cargarlos todos en memoria, por ejemplo para fusionar varios archivos de logs ordenados por fecha.&lt;br /&gt;&lt;/p&gt;El módulo heapq está disponible desde la versión de Python 2.3. A partir de la versión 2.6, Python incluye la función merge directamente en el módulo heapq, que hace lo mismo que la función imerge aquí presentada.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Referencias&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://code.activestate.com/recipes/491285" target="_blank"&gt;http://code.activestate.com/recipes/491285/&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://docs.python.org/library/heapq.html" target="_blank"&gt;http://docs.python.org/library/heapq.html&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Priority_queue" target="_blank"&gt;http://en.wikipedia.org/wiki/Priority_queue&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-2993557364638490463?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/2993557364638490463/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=2993557364638490463' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2993557364638490463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2993557364638490463'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/12/fusionando-secuencias-ordenedas-con_08.html' title='Fusionando secuencias ordenedas con Python'/><author><name>Pablo Carballo</name><uri>http://www.blogger.com/profile/02063552511346233158</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-6758666435383461909</id><published>2009-12-04T03:08:00.000-03:00</published><updated>2009-12-04T03:08:00.507-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Tabla periódica de Perl 6</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ozonehouse.com/mark/periodic/"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 282px;" src="http://2.bp.blogspot.com/_PyuhTLDSZLs/SxC-q6CItJI/AAAAAAAAAJ4/HmPX11C8ghU/s400/Periodic+Table+of+the+Operators+A4+300dpi.jpg" alt="" id="BLOGGER_PHOTO_ID_5409032796813964434" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-6758666435383461909?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/6758666435383461909/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=6758666435383461909' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6758666435383461909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6758666435383461909'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/12/tabla-periodica-de-perl-6.html' title='Tabla periódica de Perl 6'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_PyuhTLDSZLs/SxC-q6CItJI/AAAAAAAAAJ4/HmPX11C8ghU/s72-c/Periodic+Table+of+the+Operators+A4+300dpi.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-3942741300016920665</id><published>2009-12-01T02:51:00.000-03:00</published><updated>2009-12-01T02:51:00.752-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Reflexión y Opinión'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Dilbert: GUI button</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/SxC6vBSAZKI/AAAAAAAAAJw/4XCwV5K4MUo/s1600/dilbert_gui_button.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 432px; height: 148px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/SxC6vBSAZKI/AAAAAAAAAJw/4XCwV5K4MUo/s400/dilbert_gui_button.gif" alt="" id="BLOGGER_PHOTO_ID_5409028469432542370" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;Traducción:&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;- ¿Por qué agregaste este botón a la interfaz?&lt;br /&gt;- Porque usted me lo pedió.&lt;/li&gt;&lt;li&gt;- ¿Por qué pediría eso?&lt;br /&gt;- Siempre sugiere cambios aleatorios para crear la ilusión de "valor agregado".&lt;/li&gt;&lt;li&gt;- Quita el botón.&lt;br /&gt;- Sólo está en su copia.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-3942741300016920665?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/3942741300016920665/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=3942741300016920665' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/3942741300016920665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/3942741300016920665'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/12/dilbert-gui-button.html' title='Dilbert: GUI button'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PyuhTLDSZLs/SxC6vBSAZKI/AAAAAAAAAJw/4XCwV5K4MUo/s72-c/dilbert_gui_button.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-6521683805385972475</id><published>2009-11-13T14:46:00.005-03:00</published><updated>2009-11-13T14:57:52.790-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><title type='text'>Firefox es un panda</title><content type='html'>&lt;p&gt;Fuente: &lt;a href="http://tintafantasma.net/2005/03/26/firefox-es-un-panda-no-un-zorro/"&gt;tintafantasma&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Desde que salió este estupendo navegador, los usuarios que lo usan ha ido creciendo por monton, sin embargo pocos son los que conocen lo que realmente es un firefox. La mayoria de las personas lo llaman (en nuestra lengua) como &lt;em&gt;“zorro de fuego&lt;/em&gt;&lt;em&gt;”&lt;/em&gt;, &lt;em&gt;“zorro incandesente”&lt;/em&gt;, etc; gracias al logo del Firefox visto a “simple vista&lt;em&gt;”&lt;/em&gt;, sin embargo, ¿es realmente un zorro lo que vemos en ese logo?&lt;/p&gt; &lt;p&gt;Según &lt;a href="http://www.statenislandzoo.org/red_panda.html"&gt;Stateinslandzoo.org&lt;/a&gt;, &lt;a href="http://www.wellingtonzoo.com/animals/animals/mammals/panda.html"&gt;Wellingtonzoo.com&lt;/a&gt; y &lt;a href="http://iraszl.brinkster.net/creativebits/2004/09/firefox-is-not-fox.html"&gt;CreativeBits&lt;/a&gt;, firefox es el nombre que se le da en chino al panda rojo.&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt; The Chinese name for red panda is hunho or &lt;em&gt;firefox&lt;/em&gt;, due to their colour and similar size to a fox. &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt; En &lt;a href="http://en.wikipedia.org/wiki/Red_panda"&gt;Wikipedia (ingles)&lt;/a&gt; también se afirma.&lt;/p&gt; &lt;p&gt;Si vemos bien al firefox (panda rojo), podemos ver que hay un gran parecido con el logo del navegador firefox…&lt;br /&gt;&lt;img src="http://www.travelsinparadise.com/australia/sydney/pictures/zoo-red-panda-01.jpg" alt="Panda Rojo" width="400px" /&gt;&lt;br /&gt;Vs.&lt;br /&gt;&lt;img src="http://images.techtree.com/ttimages/story/firefox-logo.jpg" alt="Firefox" style="" /&gt;&lt;br /&gt;&lt;br /&gt;Fijense, ambos tienen un color similar, ambos tienen una orejitas puntiagudas, cola larga, nariz negrita, incluso fijense en la redondez de las patitas en ambos casos.&lt;br /&gt;Ahora habrá que llamarlo…panda de fuego o panda rojo.&lt;/p&gt; &lt;p&gt;&lt;br /&gt;&lt;img src="http://www.travelsinparadise.com/australia/sydney/pictures/zoo-red-panda-02.jpg" alt="" style="width: 273px;" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Post editado:&lt;/strong&gt;&lt;br /&gt;Y bueno tampoco nos hemos dado cuenta de las FAQ’s del mismo Firefox….&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;What’s a Firefox?&lt;br /&gt;&lt;br /&gt;A “Firefox” is another name for the red panda. &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Ver &lt;a href="http://www.mozilla.org/projects/firefox/firefox-name-faq.html"&gt;FAQ’s de Firefox&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Saludos&lt;br /&gt;The Ghost&lt;/strong&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-6521683805385972475?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/6521683805385972475/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=6521683805385972475' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6521683805385972475'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6521683805385972475'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/11/firefox-es-un-panda.html' title='Firefox es un panda'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4532979531360973648</id><published>2009-11-11T08:00:00.000-03:00</published><updated>2009-11-11T08:00:02.340-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lenguaje C'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>El tutorial más corto sobre Autoconf y Automake</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_PyuhTLDSZLs/SvdK94s1baI/AAAAAAAAAJg/TVFWT7iobak/s1600-h/gnu.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 259px; height: 253px;" src="http://2.bp.blogspot.com/_PyuhTLDSZLs/SvdK94s1baI/AAAAAAAAAJg/TVFWT7iobak/s400/gnu.png" alt="" id="BLOGGER_PHOTO_ID_5401868705107111330" border="0" /&gt;&lt;/a&gt;Traducción del &lt;a href="http://smalltalk.gnu.org/blog/bonzinip/all-you-should-really-know-about-autoconf-and-automake"&gt;artículo de Paolo Bonzini&lt;/a&gt; (2 de Noviembre del 2009).&lt;br /&gt;&lt;br /&gt;El problema con autotools es que se usa para cosas complicadas, y los programadores copian y pegan cosas complicadas aún cuando deben hacer algo simple. El 99% de los programadores sólo necesita acceder a los archivos .pc y generar sencillos Makefiles. De la parte de la portabilidad se encarga glib, sdl, etc.&lt;br /&gt;&lt;br /&gt;Se puede usar los siguientes archivos autotools, de sólo 9 líneas, para comenzar desde allí y agregar más cosas luego (incluyendo libtool).&lt;br /&gt;&lt;ul&gt;&lt;li&gt; configure.ac:&lt;/li&gt;&lt;/ul&gt;  &lt;pre&gt;AC_INIT([package], [version])&lt;br /&gt;AM_INIT_AUTOMAKE([foreign subdir-objects])&lt;br /&gt;AC_CONFIG_SRCDIR([configure.ac])&lt;br /&gt;AC_CONFIG_HEADERS([config.h])     # no es realmente necesario&lt;br /&gt;AC_PROG_CC                        # o AC_PROG_CXX&lt;br /&gt;AC_CONFIG_FILES([Makefile])&lt;br /&gt;AC_OUTPUT&lt;/pre&gt;  &lt;ul&gt;&lt;li&gt; Makefile.am:&lt;/li&gt;&lt;/ul&gt;  &lt;pre&gt;bin_PROGRAMS = hello&lt;br /&gt;hello_SOURCES = hello.c&lt;/pre&gt;  &lt;p&gt;Suficiente para ejecutar:&lt;/p&gt;  &lt;pre&gt;$ autoreconf -fvi&lt;br /&gt;$ ./configure&lt;br /&gt;$ make&lt;/pre&gt;  &lt;p&gt;Para cada paquete que se necesite, se debe agregar:&lt;/p&gt;  &lt;pre&gt;PKG_CHECK_MODULES([cairo], [cairo])&lt;br /&gt;PKG_CHECK_MODULES([fontconfig], [fontconfig])&lt;/pre&gt;  &lt;p&gt;y&lt;/p&gt;  &lt;pre&gt;AM_CFLAGS = $(cairo_CFLAGS) $(fontconfig_CFLAGS)&lt;br /&gt;LIBS += $(cairo_LIBS) $(fontconfig_LIBS)&lt;/pre&gt;  &lt;p&gt;respectivamente en configure.ac (luego de AC_PROG_CC) y Makefile.am.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4532979531360973648?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4532979531360973648/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4532979531360973648' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4532979531360973648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4532979531360973648'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/11/el-tutorial-mas-corto-sobre-autoconf-y.html' title='El tutorial más corto sobre Autoconf y Automake'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_PyuhTLDSZLs/SvdK94s1baI/AAAAAAAAAJg/TVFWT7iobak/s72-c/gnu.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-1548501050269364359</id><published>2009-11-09T08:00:00.001-03:00</published><updated>2009-11-09T08:00:04.714-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><category scheme='http://www.blogger.com/atom/ns#' term='Videojuegos'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>El juego más fácil del mundo</title><content type='html'>Hace unas semanas escribí sobre &lt;a href="http://programacionbizarra.blogspot.com/2009/09/el-juego-mas-dificil-del-mundo.html"&gt;el juego más difícil del mundo&lt;/a&gt;. Para los que se frustraron intentando pasar algún nivel, acá les traigo otro para saciar la sed de revancha...&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.mabuhaynet.com/easiestgame/easiest2.html"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 280px;" src="http://2.bp.blogspot.com/_PyuhTLDSZLs/SvdPcxL9nEI/AAAAAAAAAJo/gan2xm5BuGg/s400/easiest-game.png" alt="" id="BLOGGER_PHOTO_ID_5401873633712643138" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-1548501050269364359?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/1548501050269364359/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=1548501050269364359' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1548501050269364359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1548501050269364359'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/11/el-juego-mas-facil-del-mundo.html' title='El juego más fácil del mundo'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_PyuhTLDSZLs/SvdPcxL9nEI/AAAAAAAAAJo/gan2xm5BuGg/s72-c/easiest-game.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4276328543354241832</id><published>2009-11-07T16:27:00.001-03:00</published><updated>2009-11-07T16:31:00.368-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Java Hashing</title><content type='html'>Fuente: &lt;a href="http://ww.dosideas.com/java/758-java-hashing.html"&gt;Dos Ideas&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;table class="contentpaneopen"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;span class="small"&gt;Escrito por Leonardo De Seta  &lt;/span&gt;       &lt;/td&gt; &lt;/tr&gt;  &lt;tr&gt;  &lt;td class="createdate" valign="top"&gt;   Martes 27 de Octubre de 2009 10:22 &lt;/td&gt; &lt;/tr&gt;   &lt;tr&gt; &lt;td valign="top"&gt; &lt;p&gt;&lt;img alt="Equals" src="http://www.dosideas.com/images/stories/java/equals.png" align="left" width="128" height="128" hspace="10" /&gt;Todos los objetos en Java tiene dos métodos muy importantes: el método &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; y el método &lt;span style="font-family:Courier New;"&gt;equals()&lt;/span&gt;. Estos métodos están diseñados para ser sobreescritos de acuerdo a su contrato general.&lt;/p&gt; &lt;p&gt;En este artículo veremos porqué y cómo sobreescribir el método &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; que cumpla con el contrato para los HashCode.&lt;/p&gt;    &lt;h1&gt;El contrato de un HashCode&lt;/h1&gt; &lt;p&gt;El contrato del hashCode() dice: &lt;/p&gt; &lt;p style="margin-left: 40px;"&gt;&lt;strong&gt;"Si dos objetos son iguales usando &lt;span style="font-family:Courier New;"&gt;equals()&lt;/span&gt;, entonces la invocación a &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; de ambos objetos debe retornar el mismo valor"&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Entonces, la pregunta que surge es: ¿es necesario que siempre se cumpla esa oración?&lt;/p&gt; &lt;p&gt;Consideremos una clase que tiene una implementación correcta del método &lt;span style="font-family:Courier New;"&gt;equals()&lt;/span&gt;, ¿qué pasaría si no obedecemos el contrato anterior?&lt;/p&gt; &lt;p&gt;Para responder a esa pregunta, vamos a tener que considerar dos situaciones: &lt;/p&gt; &lt;ol&gt;&lt;li&gt;Objetos que son iguales, pero retornan diferentes hashCodes&lt;/li&gt;&lt;li&gt;Objetos que no son iguales, pero retornan el mismo hashCode&lt;/li&gt;&lt;/ol&gt; &lt;h3&gt;Objetos que son iguales, pero retornan diferentes hashCodes&lt;/h3&gt; &lt;p&gt;¿Qué pasaría si dos objetos son iguales (invocando &lt;span style="font-family:Courier New;"&gt;equals()&lt;/span&gt;) pero retornan diferentes hashCodes? El código se ejecutará a la perfección. Nunca vamos a encontrar problemas... hasta que se nos ocurra almacenar a nuestro objeto dentro de una colección como un &lt;span style="font-family:Courier New;"&gt;HashSet&lt;/span&gt; o un &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt;. Cuando hagamos esto, nos vamos a encontrar con problemas raros durante la ejecución.&lt;/p&gt; &lt;p&gt;Primero tenemos que comprender cómo funcionan las clases del tipo &lt;span style="font-family:Courier New;"&gt;HashSet &lt;/span&gt;y &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt;. Estas clases de colecciones dependen de que los objetos que son agregados cumplan con el contrato del hashCode. Vamos a obtener resultados impredecibles en tiempo de ejecución si no obedecemos el contrato y queremos almacenar estos objetos en la colección.&lt;/p&gt; &lt;p&gt;Veamos por ejemplo el &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt;. Cuando guardamos valores en un &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt;, estos valores en realidad se almacenan dentro de "baldes". Cada uno de estos baldes tiene asignado un número que lo identifica. Cuando agregamos un valor al &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt;, almacena el dato en uno de esos baldes. El balde que se usa depende del hashCode que devuelva el objeto a ser almacenado. Por ejemplo, si el método &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; del objeto retorna 49, entonces se almacena en el balde 49 dentro del &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt;.&lt;/p&gt; &lt;p&gt;Más tarde, cuando verifiquemos si la colección contiene al elemento invocando el método &lt;span style="font-family:Courier New;"&gt;contains(elemento)&lt;/span&gt;, el &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt; primero obtiene el hashCode de ese "elemento". Luego buscará el balde que corresponde a ese hashCode. Si el balde está vacio, significa que el &lt;span style="font-family:Courier New;"&gt;HashMap &lt;/span&gt;no contiene al elemento y devuelve &lt;span style="font-family:Courier New;"&gt;false&lt;/span&gt;.&lt;/p&gt; &lt;p&gt;Si hay un objeto o más dentro del balde, entonces se compara al "elemento" con todos los elementos en ese balde usando el método &lt;span style="font-family:Courier New;"&gt;equals()&lt;/span&gt;.&lt;/p&gt; &lt;h3&gt;Objetos que no son iguales, pero retornan el mismo hashCode&lt;/h3&gt; &lt;p&gt;El contrato del hashCode no dice nada sobre este caso. Por lo tanto, objetos distintos pueden devolver el mismo hashCode, pero las colecciones como los &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt; van a ser más ineficientes si se almacenan objetos diferentes con el mismo valor de hashCode.&lt;/p&gt; &lt;h2&gt;¿Por qué almacenar en baldes?&lt;/h2&gt; &lt;p&gt;Se utiliza este mecanismo de "baldes" por un tema de eficiencia. Pueden imaginarse que si todos los objetos que se agregan a un &lt;span style="font-family:Courier New;"&gt;HashMap &lt;/span&gt;se almacenaran en una única lista grande, entonces tendríamos que comparar la entrada con todos los objetos de la lista para dterminar si un elemento en particular está contenido en el &lt;span style="font-family:Courier New;"&gt;Map&lt;/span&gt;. Como se usan baldes, sólo se comparan los elementos del balde específico, y en general cada balde sólo almacena una pequeña cantidad de elementos en el &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt;.&lt;/p&gt; &lt;h1&gt;Sobreescribir el método hashCode()&lt;/h1&gt; &lt;p&gt;Puede resultar complejo escribir un buen método de hashCode() para una clase nueva.&lt;/p&gt; &lt;h3&gt;Retornar un valor fijo (es una mala idea...)&lt;/h3&gt; &lt;p&gt;Podemos implementar un método de hashCode() que devuelva un valor fijo, como por ejemplo: &lt;/p&gt; &lt;pre class="java5"&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 128, 128); font-style: italic;"&gt;//no hagan esto, genera mal rendimiento&lt;/span&gt;&lt;br /&gt;@&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Override.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;Override&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt; hashCode&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: rgb(204, 102, 204);"&gt;1&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;Este método satisface todos los requerimientos y es "legal" de acuerdo al contrato del hashCode, pero no va a resultar muy eficiente. Si se usa este método, todos los objetos se almacenarán dentro del mismo balde (el correspondiente al "1"), y cuando querramos comprobar si un objeto específico está dentro de la colección, entonces siempre se tendrá que verificar el contenido completa de dicha colección.&lt;/p&gt; &lt;p&gt;Por otro lado, si sobreescribimos el método &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; y rompemos el contrato ("dos objetos iguales con equals deben devolver el mismo hashCode"), entonces cuando se invoque el método &lt;span style="font-family:Courier New;"&gt;contains()&lt;/span&gt; podría devolver false para un elemento que se encuentra dentro de la colección, pero en un balde diferente.&lt;/p&gt; &lt;h3&gt;Método de Effective Java&lt;/h3&gt; &lt;p&gt;Joshua Bloch en su libro Effective Java nos brinda una buena guía para generar un valor de hashCode(): &lt;/p&gt; &lt;ol&gt;&lt;li&gt;Guardar alguna constante con un valor distinto al cero; por ejemplo &lt;strong&gt;17&lt;/strong&gt;, en una variable int llamada &lt;strong&gt;result&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;Para cada campo significativo f en el objeto (es decir, cada campo que se tiene en cuenta al ejecutar un &lt;span style="font-family:Courier New;"&gt;equals()&lt;/span&gt;), hacer lo siguiente:      &lt;ol&gt;&lt;li&gt;Calcular un int de hashCode para el campo:&lt;br /&gt;     &lt;ol&gt;&lt;li&gt;Si esl campo es un booleano, calcular  &lt;strong&gt;&lt;span style="font-family:Courier New;"&gt;c = (f ? 1 : 0)&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Si el campo es un byte, char, short o int, calcular &lt;strong&gt;&lt;span style="font-family:Courier New;"&gt;c = (int) f&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Si el campo es un long, calcular &lt;strong&gt;&lt;span style="font-family:Courier New;"&gt;c = (int) (f ^ (f &gt;&gt;&gt; 32))&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Si el campo es un float, calcular &lt;strong&gt;&lt;span style="font-family:Courier New;"&gt;c = Float.floatToIntBits(f)&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Si el campo es un double, calcular &lt;strong&gt;&lt;span style="font-family:Courier New;"&gt;long l = Double.doubleToLongBits(f); c = (int) (l ^ (l &gt;&gt;&gt; 32));&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Si el campo es una referencia a un objeto, calcular &lt;span style="font-family:Courier New;"&gt;&lt;strong&gt;c = f.hashCode()&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Si el campo es un array, tratar a cada elemento por separado. Es decir, calcular el hashCode de cada elemento significativo usando las reglas anteriores.&lt;/li&gt;&lt;/ol&gt;         &lt;/li&gt;&lt;li&gt;Combinar el hashCode calculado c en el paso 2.1 en un resultado como sigue: &lt;span style="font-family:Courier New;"&gt;&lt;strong&gt;result = 37 * result + c;&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;     &lt;/li&gt;&lt;li&gt;Retornar &lt;strong&gt;&lt;span style="font-family:Courier New;"&gt;result&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Mirar al hashCode() resultante y asegurarse que instancias iguales tengan el mismo hashCode.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Veamos un ejemplo de este algoritmo: &lt;/p&gt; &lt;div id="highlighter_543617"&gt; &lt;div&gt; &lt;pre class="java5"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;class&lt;/span&gt; HashTest &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;String&lt;/span&gt;&lt;/a&gt; campo1;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;short&lt;/span&gt;  campo2;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 128, 128); font-style: italic;"&gt;//resto de la clase...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; @&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Override.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;Override&lt;/span&gt;&lt;/a&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt; hashCode&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt; result = &lt;span style="color: rgb(204, 102, 204);"&gt;17&lt;/span&gt;;&lt;br /&gt;      result = &lt;span style="color: rgb(204, 102, 204);"&gt;37&lt;/span&gt;*result + campo1.&lt;span style="color: rgb(0, 102, 0);"&gt;hashCode&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;;&lt;br /&gt;      result = &lt;span style="color: rgb(204, 102, 204);"&gt;37&lt;/span&gt;*result + &lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;campo2;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; result;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;/pre&gt; &lt;p&gt;Como vemos elegimos la constante 37. La idea es ejegir un número que sea un &lt;strong&gt;número primo&lt;/strong&gt;. Podemos elegir cualquier número primo. Al usar un número primo los objetos se distribuirán mejor en los baldes. Pueden aprender más sobre este algoritmo y la distribución que genera buscando en Internet.&lt;/p&gt; &lt;h3&gt;Apache HashCodeBuilder&lt;/h3&gt; &lt;p&gt;Como estamos aprendiendo, no es siempre facil retornar un buen valor de hashCode. Por suerte existen clases que nos pueden ayudar.&lt;/p&gt; &lt;p&gt;El paquete &lt;strong&gt;&lt;span style="font-family:Courier New;"&gt;org.apache.commons.lang.builder&lt;/span&gt;&lt;/strong&gt; de Jakarta-Commons contiene la clase &lt;strong&gt;&lt;span style="font-family:Courier New;"&gt;HashCodeBuilder&lt;/span&gt;&lt;/strong&gt; que está diseñada para ayudarnos a implementar el método &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt;. Muchos desarrolladores luchan por escribir sus hashCode cuando existe esta clase que nos simplifica el proceso.&lt;/p&gt; &lt;p&gt;Así es como quedaría la clase de prueba anterior usando la clase &lt;span style="font-family:Courier New;"&gt;HashCodeBuilder&lt;/span&gt;:&lt;/p&gt; &lt;pre class="java5"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;class&lt;/span&gt; HashTest &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;String&lt;/span&gt;&lt;/a&gt; campo1;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;short&lt;/span&gt;  campo2;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 128, 128); font-style: italic;"&gt;//resto de la clase...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; @&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Override.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;Override&lt;/span&gt;&lt;/a&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt; hashCode&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; HashCodeBuilder&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(204, 102, 204);"&gt;83&lt;/span&gt;, &lt;span style="color: rgb(204, 102, 204);"&gt;7&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;&lt;br /&gt;           .&lt;span style="color: rgb(0, 102, 0);"&gt;append&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;campo1&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;&lt;br /&gt;           .&lt;span style="color: rgb(0, 102, 0);"&gt;append&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;campo2&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;&lt;br /&gt;           .&lt;span style="color: rgb(0, 102, 0);"&gt;toHashCode&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;/pre&gt; &lt;p&gt;Noten que los dos números del constructor del &lt;span style="font-family:Courier New;"&gt;HashCodeBuilder &lt;/span&gt;son dos números impares distintos a cero - estos números ayuda a evitar la colisión de valores de hashCode en otros objetos.&lt;/p&gt; &lt;p&gt;Si se necesita, se puede invocar al hashCode() de la superclase usando &lt;span style="font-family:Courier New;"&gt;appendSuper(int)&lt;/span&gt;.&lt;/p&gt; &lt;p&gt;Resulta muy facil escribir el método hashCode() usando la clase Apache &lt;span style="font-family:Courier New;"&gt;HashCodeBuilder&lt;/span&gt;.&lt;/p&gt; &lt;h2&gt;Objetos mutables como clave&lt;/h2&gt; &lt;p&gt;Como consejo general, deberíamos &lt;strong&gt;usar objetos inmutables como clave&lt;/strong&gt; en una colección. El hashCode funciona mejor cuando se calcula con datos inmutables. Si usamos objetos mutables como clave y estos objetos cambian su estado de manera que el hashcode también cambia, entonces el objeto almacenado quedará ubicado en un balde incorrecto dentro de la colección.&lt;/p&gt; &lt;p&gt;La cosa más importante a consdierar cuando se implementa el &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; es que, sin importar cuándo se invoca a este método, tiene que producir el mismo valor para un objeto en particular cada vez que se invoca. Si tenemos un escenario en donde el objeto produce un valor de &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; cuando se invoca al &lt;span style="font-family:Courier New;"&gt;put()&lt;/span&gt; del &lt;span style="font-family:Courier New;"&gt;HashMap&lt;/span&gt; y luego produce otro valor durante un &lt;span style="font-family:Courier New;"&gt;get()&lt;/span&gt;, en ese caso no podremos recuperar este objeto. Por lo tanto, si nuestro &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; depende de datos mutables en el objeto, cambiar estos datos con seguridad producirán una nueva clave al generar un &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; diferente.&lt;/p&gt; &lt;p&gt;Veamos el siguiente ejemplo: &lt;/p&gt; &lt;pre class="java5"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;class&lt;/span&gt; Empleado &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;String&lt;/span&gt;&lt;/a&gt; nombre;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt; edad;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; Empleado&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt; &lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; Empleado&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;String&lt;/span&gt;&lt;/a&gt; nombre, &lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt; edad&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;nombre&lt;/span&gt; = nombre;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;edad&lt;/span&gt; = edad;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;String&lt;/span&gt;&lt;/a&gt; getNombre&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; nombre;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;void&lt;/span&gt; setNombre&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;String&lt;/span&gt;&lt;/a&gt; nombre&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;nombre&lt;/span&gt;= nombre;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt; getEdad&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; edad;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;void&lt;/span&gt; setEdad&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt; edad&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;this&lt;/span&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;edad&lt;/span&gt; = edad;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; @&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Override.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;Override&lt;/span&gt;&lt;/a&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;boolean&lt;/span&gt; equals&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;a href="http://www.google.com/search?sitesearch=java.sun.com&amp;amp;q=allinurl%3Aj2se%2F1+5+0%2Fdocs%2Fapi+Object"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;Object&lt;/span&gt;&lt;/a&gt; obj&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(177, 177, 0);"&gt;if&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;obj &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;instanceof&lt;/span&gt; Empleado&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;           Empleado emp = &lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;Empleado&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;obj;&lt;br /&gt;           &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;emp.&lt;span style="color: rgb(0, 102, 0);"&gt;nombre&lt;/span&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;equals&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;nombre&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &amp;amp;&amp;amp; emp.&lt;span style="color: rgb(0, 102, 0);"&gt;edad&lt;/span&gt; == edad&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;;&lt;br /&gt;      &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: rgb(177, 51, 102);"&gt;false&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; @&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Override.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;Override&lt;/span&gt;&lt;/a&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;int&lt;/span&gt; hashCode&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; nombre.&lt;span style="color: rgb(0, 102, 0);"&gt;length&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; + edad;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;static&lt;/span&gt; &lt;span style="color: rgb(153, 51, 51);"&gt;void&lt;/span&gt; main&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;String&lt;/span&gt;&lt;/a&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;[&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;]&lt;/span&gt; args&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;{&lt;/span&gt;   &lt;br /&gt;      Empleado e = &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; Empleado&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"muhammad"&lt;/span&gt;, &lt;span style="color: rgb(204, 102, 204);"&gt;24&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;;&lt;br /&gt;      &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Map.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;Map&lt;/span&gt;&lt;/a&gt; map = &lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/HashMap.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;HashMap&lt;/span&gt;&lt;/a&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;;&lt;br /&gt;      map.&lt;span style="color: rgb(0, 102, 0);"&gt;put&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;e, &lt;span style="color: rgb(255, 0, 0);"&gt;"Muhammad Ali Khojaye"&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;;                &lt;br /&gt;&lt;br /&gt;      &lt;span style="color: rgb(128, 128, 128); font-style: italic;"&gt;// encuentra el resultado&lt;/span&gt;&lt;br /&gt;      &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;System&lt;/span&gt;&lt;/a&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;out&lt;/span&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;println&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;map.&lt;span style="color: rgb(0, 102, 0);"&gt;get&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;e&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;      e.&lt;span style="color: rgb(0, 102, 0);"&gt;nombre&lt;/span&gt; = &lt;span style="color: rgb(255, 0, 0);"&gt;"abid"&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;span style="color: rgb(128, 128, 128); font-style: italic;"&gt;// el map devolverá null porque no lo encuentra&lt;/span&gt;&lt;br /&gt;      &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;System&lt;/span&gt;&lt;/a&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;out&lt;/span&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;println&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;map.&lt;span style="color: rgb(0, 102, 0);"&gt;get&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;e&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;span style="color: rgb(128, 128, 128); font-style: italic;"&gt;// otra vez devolverá null&lt;/span&gt;&lt;br /&gt;      &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html"&gt;&lt;span style="color: rgb(170, 170, 221); font-weight: bold;"&gt;System&lt;/span&gt;&lt;/a&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;out&lt;/span&gt;.&lt;span style="color: rgb(0, 102, 0);"&gt;println&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;map.&lt;span style="color: rgb(0, 102, 0);"&gt;get&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; Empleado&lt;span style="color: rgb(102, 204, 102);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;"muhammad"&lt;/span&gt;, &lt;span style="color: rgb(204, 102, 204);"&gt;24&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;)&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 204, 102);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;Vemos en el ejemplo anterior que obtenemos algunos resultados extraños. Después de cambiar el campo nombre, el cálculo del &lt;span style="font-family:Courier New;"&gt;hashCode()&lt;/span&gt; devuelve un nuevo número y apuntará a un nuevo balde, por lo que el &lt;span style="font-family:Courier New;"&gt;contains()&lt;/span&gt; devolverá false.&lt;/p&gt; &lt;p&gt;Podemos arreglar esta situación usando alguna de estas alternativas:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;&lt;strong&gt;El hashcode es mejor calcularlo con datos inmutables&lt;/strong&gt;; por lo tanto, asegurarnos que sólo usaremos objetos inmutables como claves de una colección.&lt;/li&gt;&lt;li&gt;Implementar el hashCode() usando la primer técnica: devolver un valor constante. En este caso tenemos que ser conscientes que estamos quitando todas las ventajas del mecanismo de baldes de las colecciones.&lt;/li&gt;&lt;li&gt;Si necesitamos incluiir campos mutables en el método de hashCode(), entonces podemos calcular y almacenar el valor del hash cuando se crea el objeto, y cada vez que se actualiza alguno de los campos mutables, primero debemos quitarlo de la colección y luego agregarlo nuevamente una vez hecho el cambio.&lt;/li&gt;&lt;/ul&gt; &lt;h5&gt;Traducido de &lt;a href="http://java.dzone.com/articles/java-hashing"&gt;Java Hashing, publicado en DZone&lt;/a&gt;.&lt;/h5&gt; &lt;/div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4276328543354241832?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4276328543354241832/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4276328543354241832' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4276328543354241832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4276328543354241832'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/11/java-hashing.html' title='Java Hashing'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-6497334059829403331</id><published>2009-11-04T08:13:00.003-03:00</published><updated>2009-11-04T08:29:45.822-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><title type='text'>awk continúa pateando traseros</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_PyuhTLDSZLs/SvFk4lt8rQI/AAAAAAAAAJY/GdEvgC_6EIA/s1600-h/awk.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 288px;" src="http://2.bp.blogspot.com/_PyuhTLDSZLs/SvFk4lt8rQI/AAAAAAAAAJY/GdEvgC_6EIA/s400/awk.jpg" alt="" id="BLOGGER_PHOTO_ID_5400208351554219266" border="0" /&gt;&lt;/a&gt;En comp.programming alguién envió un interesante programa de perl para imprimir sólo la primera aparición de cada línea (o sea, eliminar líneas repetidas) de un archivo preservando el orden de las mismas (o sea, no teniendo que ordenar el archivo previamente).&lt;br /&gt;&lt;br /&gt;Recordemos que la mayoría de las veces esta tarea se realiza con el comando de Unix "uniq", que requiere que se ordene el archivo previamente con el comando "sort".&lt;br /&gt;&lt;br /&gt;La línea es:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;perl -ne 'print $_ unless $seen{$_}++'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Muy bueno. Sin embargo alguién respondió con la siguiente línea de awk:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;awk '!o[$0]++'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;¡¡¡IN-CRE-í-BLE!!!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-6497334059829403331?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/6497334059829403331/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=6497334059829403331' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6497334059829403331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6497334059829403331'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/11/awk-continua-pateando-traseros.html' title='awk continúa pateando traseros'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_PyuhTLDSZLs/SvFk4lt8rQI/AAAAAAAAAJY/GdEvgC_6EIA/s72-c/awk.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-7162358604641713011</id><published>2009-11-02T07:00:00.001-03:00</published><updated>2009-11-04T08:32:08.437-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><title type='text'>Gadgets en abowman.com</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/Su4RKjVInVI/AAAAAAAAAJQ/nBOOfCgPH6E/s1600-h/abowman.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 210px; height: 400px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/Su4RKjVInVI/AAAAAAAAAJQ/nBOOfCgPH6E/s400/abowman.png" alt="" id="BLOGGER_PHOTO_ID_5399271876244053330" border="0" /&gt;&lt;/a&gt;El programador &lt;a href="http://abowman.com/about/"&gt;Adam Bowman&lt;/a&gt; ofrece gadgets muy locos para decorar blogs, entre otras cosas, en &lt;a href="http://abowman.com/google-modules/"&gt;este sitio&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-7162358604641713011?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/7162358604641713011/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=7162358604641713011' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/7162358604641713011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/7162358604641713011'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/11/gadgets-en-abowmancom.html' title='Gadgets en abowman.com'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PyuhTLDSZLs/Su4RKjVInVI/AAAAAAAAAJQ/nBOOfCgPH6E/s72-c/abowman.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-5000356717467114098</id><published>2009-10-29T07:00:00.001-03:00</published><updated>2009-11-04T08:32:46.826-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tcl/Tk'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Tcl/Tk, un lenguaje con actitud de rock</title><content type='html'>Sin dudas el más grande invento desde los pañales descartables. Tcl/Tk es un lenguaje interpretado 100% libre creado por el profesor &lt;a href="http://home.pacbell.net/ouster/"&gt;John K. Ousterhout&lt;/a&gt; en la universidad de California, que permite escribir scripts y programas de mayor complejidad con interfaces gráficas, sockets, bases de datos y decenas de extensiones para hacer de todo muy fácilmente.&lt;br /&gt;&lt;br /&gt;Tcl/Tk se encuentra disponible para casi todas las plataformas, desde Linux hasta Windorch, pasando por Mac. Para programar en Tcl/Tk no hace falta ninguna herramienta especial, ni IDE. Sólo crear un archivo de texto nuevo, escribir nuestro código, y listo, si tenemos instalado el interprete ya se puede ejecutar.&lt;br /&gt;&lt;br /&gt;Probablemente hay muchas razones por las que Tcl/Tk es popular, pero quiero nombrar algunas de las que dice en &lt;a href="http://www.tcl.tk/about/features.html"&gt;el propio sitio&lt;/a&gt;:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Desarrollo Rápido:&lt;/span&gt; la razón más importante por la cual la gente usa Tcl es que consigue realizar su trabajo más rápido. En muchos casos, usted puede implementar aplicaciones 5-10x más rápido con Tcl que con otros lenguajes, especialmente si la aplicación utiliza interfaces gráficas, manejo de "strings", estructuras dinámicas de datos, sockets o requiere integración.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Interfaces Gráficas:&lt;/span&gt; con Tk, Tcl ofrece facilidades para la creación de interfaces gráficas que son increíblemente simples pero muy potentes.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Multiplataforma:&lt;/span&gt; Tcl/Tk se ejecuta en Windows, Macintosh, y casi todas las plataformas Unix que se pueda imaginar. Proporciona API de alto nivel que le permite escribir código que funciona de la misma - en todas partes -, mientras que en Tcl/Tk se preocupa por respetar las diferencias de plataforma, como el aspecto y comportamiento nativo para el GUI.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Fácil de aprender:&lt;/span&gt;  Tcl es un lenguaje muy simple. Los programadores experimentados pueden aprender Tcl y producir su primera aplicación interesante en tan sólo unas pocas horas o días. Los programadores casuales también puede aprender Tcl rápidamente.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Madurez:&lt;/span&gt;  Tcl/Tk ha estado bajo continuo y activo desarrollo y uso por un gran grupo de expertos desde la década de 1990.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Deploy o Despliegue:&lt;/span&gt; los lenguajes dinámicos a menudo hacen más difícil la implementación, porque usted necesita obtener tanto el intérprete del lenguaje, las bibliotecas y la aplicación en cada máquina donde se ejecutará. Tcl/Tk ofrece soluciones muy interesantes para empaquetar todo esto en un único archivo ejecutable de poco más de 1MB.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Abundancia de bibliotecas:&lt;/span&gt; decenas de bibliotecas maduras, para hacer muchas cosas.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;La comunidad:&lt;/span&gt; otra de las razones atractivas para el uso de Tcl es la gran comunidad de usuarios y desarrolladores que posee. La &lt;a href="http://wiki.tcl.tk/"&gt;wiki&lt;/a&gt; es una fuente inagotable de recursos. También cuenta con un numeroso y solidario grupo de hackers, comp.lang.tcl, al que se puede recurrir cuando uno no encuentra soluciones.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;¡Es Software Libre!&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Como contra podría mencionar que hay muy pocos recursos en español, por lo que exige que conozcamos inglés básico.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Para mostrar la eficacia del lenguaje, copio de la wiki esta &lt;a href="http://wiki.tcl.tk/1270"&gt;calculadora:&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/SqXVO29YjYI/AAAAAAAAAGY/wnnHs5BkmYI/s1600-h/calculadora.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 206px; height: 177px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/SqXVO29YjYI/AAAAAAAAAGY/wnnHs5BkmYI/s400/calculadora.png" alt="" id="BLOGGER_PHOTO_ID_5378939781211786626" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;y el código de menos de 50 líneas:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/SqXVonetLPI/AAAAAAAAAGg/KPUaiprlhQk/s1600-h/calc.tcl.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 571px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/SqXVonetLPI/AAAAAAAAAGg/KPUaiprlhQk/s400/calc.tcl.png" alt="" id="BLOGGER_PHOTO_ID_5378940223733181682" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;¿Por dónde comenzar?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En la &lt;a href="http://wiki.tcl.tk/"&gt;wiki&lt;/a&gt; hay varios recursos y enlaces a tutoriales. Me pareció que &lt;a href="http://www.bin-co.com/tcl/tutorial/contents.php"&gt;http://www.bin-co.com/tcl/tutorial/contents.php&lt;/a&gt; estaba más o menos bien. Aunque es en inglés, casi no se encuentran recursos en español para este lenguaje.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;¿Dónde consigo Tcl/Tk?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Si está usando GNU/Linux, probablemente esté instalado o se encuentra en el repositorio de su distribución. Si está usando windorch, puede descargar &lt;a href="http://www.activestate.com/activetcl/"&gt;ActiveTcl&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;En este sitio he publicado un par de programitas hechos en Tcl/Tk, por lo que se pueden ver las &lt;a href="http://programacionbizarra.blogspot.com/search/label/Tcl%2FTk"&gt;entradas marcadas con dicha etiqueta&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-5000356717467114098?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/5000356717467114098/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=5000356717467114098' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5000356717467114098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5000356717467114098'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/10/tcltk-un-lenguaje-con-actitud-de-rock.html' title='Tcl/Tk, un lenguaje con actitud de rock'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PyuhTLDSZLs/SqXVO29YjYI/AAAAAAAAAGY/wnnHs5BkmYI/s72-c/calculadora.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4659296238073086292</id><published>2009-10-27T07:28:00.000-03:00</published><updated>2009-10-27T07:28:00.886-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Los lenguajes más populares</title><content type='html'>El sitio &lt;a href="http://langpop.com/"&gt;http://langpop.com/&lt;/a&gt; recopila datos acerca de los lenguajes de programación más populares.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4659296238073086292?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4659296238073086292/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4659296238073086292' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4659296238073086292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4659296238073086292'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/10/los-lenguajes-mas-populares.html' title='Los lenguajes más populares'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-9068319484706146219</id><published>2009-10-24T17:24:00.001-03:00</published><updated>2009-10-24T17:33:04.924-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Presentación de Log4j</title><content type='html'>&lt;div style="width:425px;text-align:left" id="__ss_2027121"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/Emmerson_Miranda/log4j-1215-short-manual" title="Log4j 1.2.15 Short Manual"&gt;Log4j 1.2.15 Short Manual&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=log4j-1-2-15-shortmanual-090920143931-phpapp02&amp;stripped_title=log4j-1215-short-manual" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=log4j-1-2-15-shortmanual-090920143931-phpapp02&amp;stripped_title=log4j-1215-short-manual" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/Emmerson_Miranda"&gt;Emmerson Miranda&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-9068319484706146219?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/9068319484706146219/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=9068319484706146219' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/9068319484706146219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/9068319484706146219'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/10/presentacion-de-log4j.html' title='Presentación de Log4j'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-8472683360228248408</id><published>2009-10-24T17:03:00.002-03:00</published><updated>2009-10-24T17:09:13.370-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programa'/><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><title type='text'>Construye tu propia tira cómica online</title><content type='html'>Fuente: &lt;a href="http://oloblogger.blogspot.com/2009/09/construye-tu-propia-tira-comica-online.html"&gt;Oloblogger&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Seguro que alguna vez hemos dejado de publicar un buen chiste que se nos pasó por la cabeza, simplemente porque no somos muy mañosos para el dibujo.&lt;br /&gt;&lt;br /&gt;Esto se ha acabado porque hay muchas páginas que ofrecen herramientas para crear tu propia tira, así que el que no lo haga a partir de ahora es porque no le da la gana.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://monkeydyne.com/rmcs/buildmeat.html" target="blank"&gt;Monkey Dyne&lt;/a&gt; nos ofrece una forma muy sencilla de combinar personajes y texto. Aunque muy limitado, para diálogos de dos personajes resulta suficiente. Estos ya están diseñados y sólo hay que elegir cual ponemos a la izquierda y cual a la derecha. Admite hasta un bocadillo por personaje para cada una de las tres viñetas posibles.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_0eC4K-qZ7AM/Sn8THtM1hHI/AAAAAAAAJbo/M2Fsm3dqbG8/s1600-h/copypaste.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 550px;" src="http://1.bp.blogspot.com/_0eC4K-qZ7AM/Sn8THtM1hHI/AAAAAAAAJbo/M2Fsm3dqbG8/s1600/copypaste.jpg" alt="" id="BLOGGER_PHOTO_ID_5368030303962367090" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;En &lt;a href="http://www.wittycomics.com/make-comic.php" target="blank"&gt;Witty  Comics&lt;/a&gt; ya tenemos 48 personajes distintos y 60 fondos para elegir. Posibilidad de cambiar el bocadillo según sea un texto normal, pensamiento, grito o susurro. Personajes dibujados tipo años 70 y otros basados en animales. Previsualización directa.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_0eC4K-qZ7AM/Sn8TSgiHFEI/AAAAAAAAJbw/0ntqNiiDKTI/s1600-h/el+informe.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 550px;" src="http://3.bp.blogspot.com/_0eC4K-qZ7AM/Sn8TSgiHFEI/AAAAAAAAJbw/0ntqNiiDKTI/s1600/el+informe.jpg" alt="" id="BLOGGER_PHOTO_ID_5368030489540498498" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://stripgenerator.com/" target="blank"&gt;Strip  Generator&lt;/a&gt; tiene unos personajes mezcla de la Familia Adams y las Supernenas, pero permite mayor flexibilidad a la hora de crear y colocar los personajes. Con un catálogo aceptable de personajes, objetos y bocadillos, también permite cambiar los tamaños, rotar y la superposición de elementos.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_0eC4K-qZ7AM/Sn8bwFOv1_I/AAAAAAAAJb4/-Lvfnjeqpqw/s1600-h/problemas+relacion.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 550px;" src="http://1.bp.blogspot.com/_0eC4K-qZ7AM/Sn8bwFOv1_I/AAAAAAAAJb4/-Lvfnjeqpqw/s1600/problemas+relacion.jpg" alt="" id="BLOGGER_PHOTO_ID_5368039793700624370" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_0eC4K-qZ7AM/Sn8rMf1MjiI/AAAAAAAAJcQ/H46yWK0B2nQ/s1600-h/pixton.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 169px; height: 80px;" src="http://3.bp.blogspot.com/_0eC4K-qZ7AM/Sn8rMf1MjiI/AAAAAAAAJcQ/H46yWK0B2nQ/s400/pixton.jpg" alt="" id="BLOGGER_PHOTO_ID_5368056774551965218" border="0" /&gt;&lt;/a&gt;&lt;a href="http://pixton.com/es/"&gt;Pixton&lt;/a&gt; tiene personajes muy simples prediseñados, que podemos personalizar algo más que en los anteriores casos: tamaño, cabello, color... e incluso cambiar la postura. La escena también es modificable y se pueden añadir objetos.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://makebeliefscomix.com/Comix/"&gt;MakeBeliefsComix&lt;/a&gt;. Prácticamente todos los elementos son personalizables. Algo más flexible en cuanto al número de viñetas porque se puede elegir entre 2 y 4. Quince personajes a elegir con variaciones en cuanto a posición y expresión. También incluye la posibilidad de rotar, cambiar tamaño y posicionar libremente.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_0eC4K-qZ7AM/Sn8hBJJJVmI/AAAAAAAAJcA/VQEJzmIAml4/s1600-h/makebeliefscomix.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 550px;" src="http://3.bp.blogspot.com/_0eC4K-qZ7AM/Sn8hBJJJVmI/AAAAAAAAJcA/VQEJzmIAml4/s1600/makebeliefscomix.jpg" alt="" id="BLOGGER_PHOTO_ID_5368045584366786146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_0eC4K-qZ7AM/Sn8k61aEj6I/AAAAAAAAJcI/QSW1fSnkTyU/s1600-h/comeeko.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 206px; height: 57px;" src="http://1.bp.blogspot.com/_0eC4K-qZ7AM/Sn8k61aEj6I/AAAAAAAAJcI/QSW1fSnkTyU/s400/comeeko.jpg" alt="" id="BLOGGER_PHOTO_ID_5368049874036363170" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.comeeko.com/"&gt;Pikistrips&lt;/a&gt;, aporta una variante que es la de subir las imágenes que quieras. Prácticamente me ha parecido un laboratorio de fotomontaje, pero adaptado al comic. Un montón de parámetros personalizables similares a los de los programas de edición de imágenes, bastantes modelos predefinidos de maquetado de viñetas y los bocadillos, que no podían faltar.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_0eC4K-qZ7AM/Sn8zavq0LBI/AAAAAAAAJcY/IL2qg-ESxP0/s1600-h/bitstrips+logo.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 124px; height: 58px;" src="http://4.bp.blogspot.com/_0eC4K-qZ7AM/Sn8zavq0LBI/AAAAAAAAJcY/IL2qg-ESxP0/s400/bitstrips+logo.jpg" alt="" id="BLOGGER_PHOTO_ID_5368065815414582290" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.bitstrips.com/"&gt;Bitstrips&lt;/a&gt; es el más completito, pero en consecuencia, el más complicado. Creo que no es recomendable para un trabajo esporádico, pero es el mejor si vas a hacer tiras con cierta frecuencia. Permite personalizar todos los rasgos de los personajes, así como su complexión, postura o vestimenta. Aunque tienes suficientes prediseñados para poder empezar, puedes crear tus propios personajes y guardarlos en tu librería personal. Muchos fondos, muchos objetos, muchos formatos de tira.&lt;br /&gt;&lt;br /&gt;En casi todos los procesos de creación se dispone de un editor básico y de otro avanzado para poder recrearse un poco más.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_0eC4K-qZ7AM/Sn8ztXONjOI/AAAAAAAAJco/2uYwLRBWLnM/s1600-h/bitstrips.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 296px;" src="http://4.bp.blogspot.com/_0eC4K-qZ7AM/Sn8ztXONjOI/AAAAAAAAJco/2uYwLRBWLnM/s400/bitstrips.jpg" alt="" id="BLOGGER_PHOTO_ID_5368066135269674210" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_0eC4K-qZ7AM/Sn8ztJ5pjCI/AAAAAAAAJcg/pjHEWIh1xhw/s1600-h/bitstrips+2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 303px;" src="http://3.bp.blogspot.com/_0eC4K-qZ7AM/Sn8ztJ5pjCI/AAAAAAAAJcg/pjHEWIh1xhw/s400/bitstrips+2.jpg" alt="" id="BLOGGER_PHOTO_ID_5368066131693767714" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-8472683360228248408?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/8472683360228248408/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=8472683360228248408' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8472683360228248408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8472683360228248408'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/10/construye-tu-propia-tira-comica-online.html' title='Construye tu propia tira cómica online'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_0eC4K-qZ7AM/Sn8THtM1hHI/AAAAAAAAJbo/M2Fsm3dqbG8/s72-c/copypaste.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-2286659510860178317</id><published>2009-10-17T17:56:00.006-03:00</published><updated>2009-10-17T18:11:43.836-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>La tabla periódica de las fuentes</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://archivos.zptweb.net/images/tabla-periodica-fuentes.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://archivos.zptweb.net/images/tabla-periodica-fuentes.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-2286659510860178317?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/2286659510860178317/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=2286659510860178317' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2286659510860178317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2286659510860178317'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/10/la-tabla-periodica-de-las-fuentes.html' title='La tabla periódica de las fuentes'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-2610693314202331917</id><published>2009-10-11T19:52:00.003-03:00</published><updated>2009-10-24T17:09:49.464-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><category scheme='http://www.blogger.com/atom/ns#' term='Cultura Libre'/><category scheme='http://www.blogger.com/atom/ns#' term='Reflexión y Opinión'/><title type='text'>¿Por qué en GNU/Linux no hay virus?</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_PyuhTLDSZLs/StJjKflyfmI/AAAAAAAAAIg/IwxF52RYGvM/s1600-h/win-virus.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 197px;" src="http://4.bp.blogspot.com/_PyuhTLDSZLs/StJjKflyfmI/AAAAAAAAAIg/IwxF52RYGvM/s400/win-virus.jpg" alt="" id="BLOGGER_PHOTO_ID_5391480735845744226" border="0" /&gt;&lt;/a&gt;El último post de &lt;a href="http://stealthissoftware.blogspot.com/2009/10/microsoft-security-essentials.html"&gt;Steal This Software&lt;/a&gt;, de donde también tomé la foto, me llevó a copiar esto de &lt;a href="http://www.wikilearning.com/tutorial/manual_faq_debian-porque_en_linux_no_hay_virus/6515-8"&gt;una FAQ de Debian&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;Los virus son la pesadilla de los administradores, cada mes aparecen mas de 30 mil y es un hecho que las actualizaciones mensuales de los antivirus no los incluyen a todos. Para los usuarios no expertos también son una molestia, los antivirus pueden hacer que una computadora pierda hasta el 30% de su veocidad. Cada año cientos de millones de dólares se pierden en horas/hombre (y horas/mujer   ;-) ) por los virus en todo el mundo.&lt;br /&gt;&lt;br /&gt;Para que un programa sea considerado como un virus debe cumplir dos requisitos:&lt;br /&gt;&lt;br /&gt;1) Que se copie a sí mismo&lt;br /&gt;2) Que se  propague de manera "natural" entre los sistemas&lt;br /&gt;&lt;br /&gt;Los &lt;em&gt;gusanos&lt;/em&gt; son programas que aprovechan un &lt;em&gt;exploit&lt;/em&gt; (error en el código de un programa) para infiltrarse en un sistema. Los &lt;em&gt;troyanos&lt;/em&gt; son gusanos que abren un puerto trasero para permitir que una persona ajena entre al sistema. La diferencia principal entre los virus y los gusanos radica en que los virus se propagan sólos por la red, mientras que alguien (un hacker) debe realizar acciones especificas para implantar un gusano. Por cada máquina atacada por un gusano existen miles (quizás millones) de equipos infectados por virus. En GNU/Linux hay gusanos y troyanos, pero no virus.&lt;br /&gt;&lt;br /&gt;Con frecuencia he escuchado la opinion de "expertos" que argumentan que en Linux no hay virus porque hay pocos equipos con este sistema operativo, pero que en cuanto se vuelva más popular los virus aparecerán. Obviando el hecho de que Unix/Linux poseen el 40% del mercado de servidores, esta opinión revela las pobres expectativas que Microsoft le ha impuesto al usuario común, pues según éste, es normal que todos los sistemas operativos sean afectados por los virus. Pero en realidad, solo Windows padece de los virus. No todo es culpa de Microsoft, no ha sido fácil llevar a un sistema operativo tan deficiente como Windows95 al exigente mundo de los servidores: en busca de un buen desempeño, se ha debido de pagar un precio en la seguridad de Windows XP y Windows 2003, quizás un precio demasiado alto.&lt;br /&gt;&lt;br /&gt;El hecho, sin embargo, es que en Linux no hay ni habrá virus, (la verdad es que en ningún sistema operativo &lt;b&gt;deberían&lt;/b&gt; de existir los virus), la razón radica en la gestión de memoria y la asignacion de permisos por omisión, los cuales hacen imposible que un programa no autorizado se ejecute y propague. Varias consultoras reportan que los servidores mas atacados en Internet son los basados en Linux, y la gran mayoria sale victorioso de la prueba. Sin embargo, esto no significa que este sistema operativo sea invulnerable: los programas y el mismo kernel poseen fallas que al ser explotadas permiten que, en casos extremos, un extraño tome control del equipo. La mejor manera de prepararse para un ataque es siendo uno mismo un hacker, escaneando los puerto de nuestro server, inyectando SQL en nuestras paginas web y tratando de ejecutar codigo malicioso. Lo más importante es frecuentar sitios que informen sobre fallos de seguridad, como &lt;a class="ext" href="http://www.linuxtoday.com/"&gt;linuxtoday.com&lt;/a&gt; y buscar actualizaciones para nuestro sistema cada siete dias. Existen muchas soluciones que automatizan este proceso.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-2610693314202331917?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/2610693314202331917/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=2610693314202331917' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2610693314202331917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2610693314202331917'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/10/por-que-en-gnulinux-no-hay-virus.html' title='¿Por qué en GNU/Linux no hay virus?'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_PyuhTLDSZLs/StJjKflyfmI/AAAAAAAAAIg/IwxF52RYGvM/s72-c/win-virus.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-1688329261873459766</id><published>2009-10-09T00:25:00.005-03:00</published><updated>2009-10-24T17:10:15.991-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Curiosidad'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>El juego de la vida de Conway</title><content type='html'>Se trata de un sencillo juego matemático que publicó el británico &lt;a href="http://es.wikipedia.org/wiki/John_Conway"&gt;Conway&lt;/a&gt; en 1970.&lt;br /&gt;&lt;br /&gt;Desde un punto de vista teórico (que excede la temática de este blog), es interesante porque es equivalente a una &lt;a href="http://es.wikipedia.org/wiki/M%C3%A1quina_de_Turing" title="Máquina de Turing"&gt;máquina universal de Turing&lt;/a&gt;, es decir, todo lo que se puede computar &lt;a href="http://es.wikipedia.org/wiki/Algoritmo" title="Algoritmo"&gt;algorítmicamente&lt;/a&gt; se puede computar en el juego de la vida.&lt;br /&gt;&lt;br /&gt;Se trata de un tablero con un número infinito de casilleros. Cada casillero se denomina "célula", y puede estar viva (color negro) o muerta (color blanco), según se quiera antes de comenzar la partida.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/Ss6v3n6sTeI/AAAAAAAAAIQ/20ekzkVbaEs/s1600-h/Game_of_life_glider_gun.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 101px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/Ss6v3n6sTeI/AAAAAAAAAIQ/20ekzkVbaEs/s400/Game_of_life_glider_gun.png" alt="" id="BLOGGER_PHOTO_ID_5390439174151884258" border="0" /&gt;&lt;/a&gt;Una vez armado el tablero se da comienzo. El estado del tablero evoluciona a lo largo de unidades de tiempo discretas (se podría decir que por &lt;a href="http://es.wikipedia.org/wiki/Turno" title="Turno"&gt;turnos&lt;/a&gt;). El estado de todas las células se tiene en cuenta para calcular el estado de las mismas al turno siguiente. Todas las células se actualizan simultáneamente.&lt;br /&gt;&lt;br /&gt;Las transiciones dependen del número de células vecinas vivas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Una célula muerta con exactamente 3 células vecinas vivas "nace" (al turno siguiente estará viva).&lt;/li&gt;&lt;li&gt;Una célula viva con 2 ó 3 células vecinas vivas sigue viva, en otro caso muere o permanece muerta (por "soledad" o "superpoblación").&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_PyuhTLDSZLs/Ss6w3PoRbqI/AAAAAAAAAIY/y3xNBCAMGbs/s1600-h/Gospers_glider_gun.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 250px; height: 180px;" src="http://2.bp.blogspot.com/_PyuhTLDSZLs/Ss6w3PoRbqI/AAAAAAAAAIY/y3xNBCAMGbs/s400/Gospers_glider_gun.gif" alt="" id="BLOGGER_PHOTO_ID_5390440267143802530" border="0" /&gt;&lt;/a&gt;¡Hermoso!&lt;br /&gt;&lt;br /&gt;Hay un poco más de información en &lt;a href="http://es.wikipedia.org/wiki/Juego_de_la_vida"&gt;wikipedia&lt;/a&gt;, junto a varios enlaces de implementaciones del juego en varios lenguajes y plataformas. Pero me gustó &lt;a href="http://www.granvino.com/jam/stuff/juegos/gamoliyas/spanish/index.htm"&gt;esta&lt;/a&gt; hecha en &lt;a href="http://es.wikipedia.org/wiki/JavaScript"&gt;Javascript&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Por último no descarto que me programe yo mismo uno en java o javascript algún día de estos.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-1688329261873459766?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/1688329261873459766/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=1688329261873459766' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1688329261873459766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1688329261873459766'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/10/el-juego-de-la-vida-de-conway.html' title='El juego de la vida de Conway'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PyuhTLDSZLs/Ss6v3n6sTeI/AAAAAAAAAIQ/20ekzkVbaEs/s72-c/Game_of_life_glider_gun.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-8735596613404908222</id><published>2009-10-06T23:40:00.001-03:00</published><updated>2009-10-24T17:10:25.128-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Análisis y Diseño'/><title type='text'>El problema con la planificación</title><content type='html'>Fuente: &lt;a href="http://www.dosideas.com/reflexiones/739-el-problema-con-la-planificacion.html"&gt;Dos Ideas&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;table class="contentpaneopen"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;span class="small"&gt;Escrito por Leonardo De Seta  &lt;/span&gt;       &lt;/td&gt; &lt;/tr&gt;  &lt;tr&gt;  &lt;td class="createdate" valign="top"&gt;   Martes 06 de Octubre de 2009 09:47 &lt;/td&gt; &lt;/tr&gt;   &lt;tr&gt; &lt;td valign="top"&gt; &lt;p&gt;&lt;img src="http://www.dosideas.com/images/stories/reflexiones/mapa-de-ruta.png" alt="Mapa de ruta" align="left" width="110" height="115" hspace="10" /&gt;Creo que estoy teniendo bastante éxito con mi carrera. Pero si hubiera sido mejor con la planificación, no hubiera logrado ni la mitad de las cosas que logré! De hecho, algunas cosas ni siquiera las hubiera comenzado...&lt;/p&gt;    &lt;p&gt;Hay cosas que se pueden planificar, y otras que no. El problema es que la mayoría de las organizaciones &lt;em&gt;esperan&lt;/em&gt; tener un plan. Y esperan cumplirlo sin importar lo que ocurra. Y esto no es realista.&lt;/p&gt; &lt;p&gt;Al hacer una planificación detallada se está presuponiendo que se sabe a donde se quiere ir, y que no vamos a influenciarnos por lo que ocurra en el camino - o al menos, no sin tener que hacer una gran re-planificación. En mi experiencia, esto provoca que los líderes de proyecto tengan una visión restringida.&lt;/p&gt; &lt;p&gt;No me malinterpreten - no estoy sugiriendo que se embarquen en un proyecto que no tenga una visión clara y robusta. Y no estoy sugiriendo que se embarquen en un proyecto en donde no tienen idea de lo que hay que lograr, y si es tiene objetivos razonables (aunque si desafiante) con los recursos disponibles. Y definitívamente es una buena idea armarse de un plan de alto nivel que tenga hitos; pero es un mapa de ruta de alto nivel en vez de un plan detallado.&lt;/p&gt; &lt;p&gt;Yo vengo de un entorno de desarrollo tradicional, y soy consciente que todo eso suena bastante loco. Y admito que se necesita cierto nivel de madurez y experiencia para reconocer que no se puede planificar en detalle por adelantado si queremos mantener la flexibilidad, como así lo exigen los requerimientos reales, riesgos, problemas, prioridades y oportunidades que van apareciendo a medida que construimos el software.&lt;/p&gt; &lt;p&gt;La mayoría de las organizaciones no están listas para aceptar esta idea tan radical - la idea de aceptar que no sabemos a donde estamos yendo (al menos, no con certeza), y que no sabemos cuál va a ser el retorno de la inversión, o cuándo ocurrirá. Entonces, como mínimo, es esencial contar con una visión clara y un plan de alto nivel. Sean cuidadosos de no entrar en detalles.&lt;/p&gt; &lt;p&gt;En vez de un plan detallado, prefiero una visión fuerte, una estrategia, metas, y un mapa de ruta (un plan de alto nivel). Las tácticas para lograr esto, por ejemplo las características precisas y todas las tareas a entregar, pueden variar en el camino y es mejor no planificarlas por adelantado. Esto le permite al equipo descubrir los detalles cuando están en una mejor posición para hacerlo, y les permite cambiar la dirección rápidamente en respuesta a las circunstancias cambiantes.&lt;/p&gt; &lt;p&gt;Y, cuando lo pensamos un poco, es el significado de &lt;strong&gt;ágil&lt;/strong&gt;...&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-8735596613404908222?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/8735596613404908222/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=8735596613404908222' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8735596613404908222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8735596613404908222'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/10/el-problema-con-la-planificacion.html' title='El problema con la planificación'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4598080759280015679</id><published>2009-09-30T08:41:00.002-03:00</published><updated>2009-09-30T09:11:12.848-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tcl/Tk'/><category scheme='http://www.blogger.com/atom/ns#' term='Scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='Programa'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Café Instantáneo</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_PyuhTLDSZLs/SsNEIlBtx2I/AAAAAAAAAII/UnaAiFfaJG4/s1600-h/cafe-screenshot.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 260px;" src="http://1.bp.blogspot.com/_PyuhTLDSZLs/SsNEIlBtx2I/AAAAAAAAAII/UnaAiFfaJG4/s400/cafe-screenshot.PNG" alt="" id="BLOGGER_PHOTO_ID_5387224493434193762" border="0" /&gt;&lt;/a&gt;Café Instantáneo es la idea de utilizar scripts bastante sencillos para generar código. Surge de una necesidad personal de aumentar la productividad en el desarrollo de un par de sistemas web con Java.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Es más fácil copiar y pegar código conocido que escribirlo.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Esta necesidad se me presentó hace relativamente poco tiempo, por lo que actualmente sólo he desarrollado unas pocas horas (para ser generoso) en esta dirección. Sólo hice &lt;a href="http://hectorscripting.googlecode.com/files/instant-coffee-30sep2009.zip"&gt;este&lt;/a&gt; script &lt;a href="http://es.wikipedia.org/wiki/Tcl"&gt;Tcl/Tk&lt;/a&gt; de pocas líneas para generar fuentes a partir de plantillas.&lt;br /&gt;&lt;br /&gt;Habrá más café instantáneo en algún futuro.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4598080759280015679?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4598080759280015679/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4598080759280015679' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4598080759280015679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4598080759280015679'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/cafe-instantaneo.html' title='Café Instantáneo'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_PyuhTLDSZLs/SsNEIlBtx2I/AAAAAAAAAII/UnaAiFfaJG4/s72-c/cafe-screenshot.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-5091302333069470981</id><published>2009-09-23T19:39:00.001-03:00</published><updated>2009-09-23T19:43:02.437-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Análisis y Diseño'/><title type='text'>Cómo NO hacer programas</title><content type='html'>&lt;div style="width:425px;text-align:left" id="__ss_1688748"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/javiergs/cb894-antipatterns" title="200610 - Antipatrones de Software"&gt;200610 - Antipatrones de Software&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cb894-antipatterns-090706173927-phpapp01&amp;stripped_title=cb894-antipatterns" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cb894-antipatterns-090706173927-phpapp01&amp;stripped_title=cb894-antipatterns" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;documents&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/javiergs"&gt;Javier Gonzalez Sanchez&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-5091302333069470981?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/5091302333069470981/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=5091302333069470981' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5091302333069470981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5091302333069470981'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/como-no-hacer-programas.html' title='Cómo NO hacer programas'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-7894998413966952538</id><published>2009-09-21T17:45:00.003-03:00</published><updated>2009-09-21T17:50:28.868-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Videojuegos'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>El juego más difícil del mundo</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.jocjuegos.com/juego-el-juego-mas-dificil-del-mundo.html"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 291px;" src="http://2.bp.blogspot.com/_PyuhTLDSZLs/SrfmuOIQdRI/AAAAAAAAAIA/QiqQopvdA60/s400/juego-dificil.jpg" alt="" id="BLOGGER_PHOTO_ID_5384025561285817618" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Es impozible!!! Muy difícil!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-7894998413966952538?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/7894998413966952538/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=7894998413966952538' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/7894998413966952538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/7894998413966952538'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/el-juego-mas-dificil-del-mundo.html' title='El juego más difícil del mundo'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_PyuhTLDSZLs/SrfmuOIQdRI/AAAAAAAAAIA/QiqQopvdA60/s72-c/juego-dificil.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-3753967349321106593</id><published>2009-09-20T04:29:00.002-03:00</published><updated>2009-09-20T04:36:18.083-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Reflexión y Opinión'/><title type='text'>Unix, el sistema operativo "hackeable"</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_PyuhTLDSZLs/SrXaIc_lbKI/AAAAAAAAAH4/HUVWZw4kyIs/s1600-h/CUSTOM_LIVE-FREE-OR-DIE-UNIX.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 280px; height: 140px;" src="http://2.bp.blogspot.com/_PyuhTLDSZLs/SrXaIc_lbKI/AAAAAAAAAH4/HUVWZw4kyIs/s400/CUSTOM_LIVE-FREE-OR-DIE-UNIX.jpg" alt="" id="BLOGGER_PHOTO_ID_5383448768347991202" border="0" /&gt;&lt;/a&gt;Es indudable que Unix (en sus distintas implementaciones y clones) es el sistema operativo favorito de los hackers. Y cuando digo hackers no me refiero a los que se dedican a la seguridad informática, ya que esos son &lt;a href="http://stallman.org/articles/on-hacking.html"&gt;crackers&lt;/a&gt;, sino a los que estudian y practican la programación de computadoras por placer.&lt;br /&gt;&lt;br /&gt;La principal razón de usar Unix es que este sistema operativo ofrece un ambiente muy propicio para la programación "casual".&lt;br /&gt;&lt;br /&gt;A diferencia de otros sistemas, como MS windorch, Unix no establece una estricta barrera entre usuario y desarrollador. En windorch se da esta barrera porque el sistema no ofrece recursos para hacer programas o scripts ad hoc, como por ejemplo un buen interprete de comandos y un potente sistema de scripting. De hecho, windorch ni siquiera viene con un editor de texto decente en el que se pueda escribir una miserable línea de código.&lt;br /&gt;&lt;br /&gt;La programación en windorch requiere de adquirir algún pesado y costoso entorno de desarrollo integrado, como .NET. Muy apto para uso profesional, pero muy poco adaptado para las necesidades del desarrollador casual.&lt;br /&gt;&lt;br /&gt;Esta barrera molesta deja en claro que el sistema está pensado para que el usuario NO programe. Surge de una concepción de que el software es elaborado en un engorroso proyecto planificado y en un entorno más bien profesional, pero no a través de la escritura de pequeños programas o scripts por parte de los usuarios.&lt;br /&gt;&lt;br /&gt;Algo muy distinto pasa en el mundo del Unix, donde el sistema sí viene con muchos recursos para programar modestas soluciones a medida. Se podría decir que Unix es un sistema "hackeable" ya que ofrece buenos editores de texto, con potentes interpretes de comandos y potentes sistemas de scripting. Sólo basta con abrir un archivo nuevo, y comenzar a escribir código y listo, ya estamos programando. En Unix casi que decir usuario es decir también programador.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-3753967349321106593?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/3753967349321106593/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=3753967349321106593' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/3753967349321106593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/3753967349321106593'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/unix-el-sistema-operativo-hackeable.html' title='Unix, el sistema operativo &quot;hackeable&quot;'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_PyuhTLDSZLs/SrXaIc_lbKI/AAAAAAAAAH4/HUVWZw4kyIs/s72-c/CUSTOM_LIVE-FREE-OR-DIE-UNIX.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-1359447720695053249</id><published>2009-09-20T03:35:00.003-03:00</published><updated>2009-09-20T03:53:21.661-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Cultura Libre'/><title type='text'>El día internacional del software libre</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/SrXQplDhMeI/AAAAAAAAAHw/R3SUhwBFVZg/s1600-h/SFD09logo_mclimeorangeblend_sun_bvlshdw.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 174px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/SrXQplDhMeI/AAAAAAAAAHw/R3SUhwBFVZg/s400/SFD09logo_mclimeorangeblend_sun_bvlshdw.png" alt="" id="BLOGGER_PHOTO_ID_5383438342331380194" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.softwarefreedomday.org/"&gt;&lt;b&gt;Software Freedom Day&lt;/b&gt;&lt;/a&gt; (SFD) es una celebración anual del software libre. SFD busca no sólo celebrar las virtudes del software libre, sino que además promocionar su uso.&lt;p&gt;SFD fue creado en el 2004 y se celebró el 28 de Agosto. Desde entonces ha crecido en popularidad. En el 2008 más de 500 agrupaciones en 90 países lo festejaron.&lt;/p&gt;&lt;p&gt;Desde el 2006 se decidió que se realizara el tercer sábado de cada Septiembre: 15 de Septiembre del 2007, 20 de Septiembre del 2008, 19 de Septiembre del 2009, etc.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-1359447720695053249?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/1359447720695053249/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=1359447720695053249' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1359447720695053249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1359447720695053249'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/el-dia-internacional-del-software-libre.html' title='El día internacional del software libre'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PyuhTLDSZLs/SrXQplDhMeI/AAAAAAAAAHw/R3SUhwBFVZg/s72-c/SFD09logo_mclimeorangeblend_sun_bvlshdw.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-8456206815984027790</id><published>2009-09-16T14:50:00.001-03:00</published><updated>2009-09-16T14:52:29.215-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Reflexión y Opinión'/><title type='text'>La velocidad mata</title><content type='html'>&lt;table class="contentpaneopen"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;span class="small"&gt;Fuente: &lt;a href="http://www.dosideas.com/desarrollo-de-software/717-la-velocidad-mata.html"&gt;Dos Ideas&lt;/a&gt;&lt;br /&gt;Escrito por Leonardo De Seta  &lt;/span&gt;       &lt;/td&gt; &lt;/tr&gt;  &lt;tr&gt;  &lt;td class="createdate" valign="top"&gt;   Miércoles 16 de Septiembre de 2009 09:30 &lt;/td&gt; &lt;/tr&gt;   &lt;tr&gt; &lt;td valign="top"&gt; &lt;p&gt;&lt;img alt="Cronometro" src="http://www.dosideas.com/images/stories/desarrollo-de-software/cronometro.png" align="left" height="128" hspace="10" width="128" /&gt;Sos un programador. Eso signifca que tenés una presión tremenda por trabajar rápido. Hay fechas que cumplir. Hay bugs que arreglar antes de la gran demo. Hay calendarios productivos a los que llegar. Y tu trabajo depende de cuán rápido vayas y qué tan confiable seas para cumplir las planificaciones. Y esto significa que tenés que tomar atajos, compromisos, ser rápido y desprolijo.&lt;/p&gt; &lt;p&gt;Que estupidez.&lt;/p&gt;    &lt;p&gt;Si, me escucharon. ¡Que estupidez! &lt;strong&gt;No existe el "rápido y desprolijo" en el software. La desprolijidad significa lentitud.&lt;/strong&gt; La desprolijdad es la muerte.&lt;/p&gt; &lt;p&gt;El código malo hace que todos sean lentos. Vos lo sabes. Yo lo sé. Alguna vez, todos nos vimos retrasados por mal código. Nos volvimos lentos con mal código que escribimos hace un mes, hace dos semanas, incluso ayer. En el software hay una cosa seguro: si escribimos código malo, vamos a ir lento. Y si el código es &lt;em&gt;muy&lt;/em&gt; malo, es probable que directamente nos detengamos.&lt;/p&gt; &lt;p&gt;La única forma de ir rápido es trabajar bien.&lt;/p&gt; &lt;p&gt;Y esto es simple sentido común. Podría citar frase tras frase al respecto. Cualquier cosa que vale la pena hacer, vale la pena hacerla bien. Un lugar para cada cosa, y cada cosa en su lugar. Lento y constante ganan la carrera. Y así, y así. Tenemos siglos de sabiduría que nos dicen que apurarse es mala idea. Y sin embargo, cuando la fecha se acerca...&lt;/p&gt; &lt;p&gt;La habilidad de los profesionales es su capacidad para tener intención. Los profesionales no se apuran. Los profesionales comprenden el valor de la prolijidad y la disciplina. &lt;strong&gt;Los profesionales no escriben mal código - nunca. &lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Equipo tras equipo caen en la tentación de apresurar las cosas en su código. Equipo tras equipo usaron largas horas de sobreesfuerzo en un intento de llegar con su producto al mercado. Y equipo tras equipo destruyeron los proyectos en el intento. Los equipos que empiezan a empiezan a apresurarse y hacer milagros, a menudo terminan arrastrándose en lentitud después de unos meses. Su código está tan mezclado, tan confuso, tan acoplado, que nadie puede hacer un cambio sin romper otro ocho módulos. Nadie puede tocar un módulo sin tener que tocar otros veinte. Y cada cambio introduce un nuevo efecto secundario impredecible, junto con más bugs. Las estimaciones se estiran de días a meses. El equipo se paraliza en una lentitud mortal. Los gerentes se vuelven locos, y los desarrolladores comienzan a buscar trabajos nuevos.&lt;/p&gt; &lt;p&gt;¿Y qué pueden hacer los líderes? Pueden gritar y gritar sobre que "hay que ir más rápido". Pueden apresurar más las fechas, para causar una sensación de urgencia. Pero al final, lo único que resulta es contratar más programadores. E incluso esto no funciona siempre, porque las nuevas personas van a terminar agregando más problemas por encima del problema viejo. En poco tiempo, el equipo volvió a estar lento, en una marcha continua e inexorable hacia la Productividad Cero.&lt;/p&gt; &lt;p&gt;¿Y quien es el responsable del desastre? Los programadores. Vos. Yo. Nos apresuramos. Hicimos lio. No mantuvimos la prolijidad. No actuamos profesionalmente.&lt;/p&gt; &lt;p&gt;Si queremos ser profesionales, si amamos esta profesión, entonces &lt;em&gt;no debemos apresurarnos&lt;/em&gt;. Debemos mantener prolijo al código. Tan prolijo que casi no necesite comentarios.&lt;/p&gt; &lt;h5&gt;Traducido de &lt;a href="http://programmer.97things.oreilly.com/wiki/index.php/Speed_Kills"&gt;Speed kills, por Uncle Bob&lt;/a&gt;.&lt;/h5&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-8456206815984027790?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/8456206815984027790/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=8456206815984027790' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8456206815984027790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8456206815984027790'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/la-velocidad-mata.html' title='La velocidad mata'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-5404718552076869093</id><published>2009-09-16T00:57:00.005-03:00</published><updated>2009-09-19T02:25:13.850-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Videojuegos'/><title type='text'>I wish I were the moon</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/SrBoZGhQk_I/AAAAAAAAAHo/7bYcly2K-Yc/s1600-h/i-wish-i-were-the-moon.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 400px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/SrBoZGhQk_I/AAAAAAAAAHo/7bYcly2K-Yc/s400/i-wish-i-were-the-moon.png" alt="" id="BLOGGER_PHOTO_ID_5381916335163872242" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Extraño juego creado por el innovador desarrollador argentino independiente &lt;a href="http://www.ludomancy.com/"&gt;Daniel Benmergui&lt;/a&gt; inspirado en el cuento "La distancia de la Luna" del escritor italiano (nacido en Cuba) &lt;a href="http://es.wikipedia.org/wiki/Italo_Calvino"&gt;Italo Calvino&lt;/a&gt;. Consiste en encontrar los posibles finales de un triángulo amoroso entre dos enamorados y la luna.&lt;br /&gt;&lt;br /&gt;Lo sorprendente es el modo de juego, que imita tomar una "fotografía" con el mouse y arrastrarla para interactuar con los distintos elementos de la pantalla. Casi no se utiliza texto para comunicarse con el usuario, se trata de apelar a la intuición del jugador, lo cual ayuda a establecer un vínculo emocional.&lt;br /&gt;&lt;br /&gt;Los gráficos "retro" pixelados de bajísima resolución son increíbles. Le dan una estética muy bella ante los nostálgicos que vivieron algo de la historia de los videojuegos. Por otro parte intentan apartarse del hiperrealismo que, posibilitado por los recursos tecnológicos, nos propone un gran grupo de desarrolladores en estos tiempos.&lt;br /&gt;&lt;br /&gt;Además el juego le rinde culto a la sencillez. Probando una vez más que lo simple es mejor... Una verdadera obra de arte.&lt;br /&gt;&lt;br /&gt;Puede jugar &lt;a href="http://www.kongregate.com/games/danielben/i-wish-i-were-the-moon"&gt;aquí&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-5404718552076869093?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/5404718552076869093/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=5404718552076869093' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5404718552076869093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5404718552076869093'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/i-wish-i-were-moon.html' title='I wish I were the moon'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_PyuhTLDSZLs/SrBoZGhQk_I/AAAAAAAAAHo/7bYcly2K-Yc/s72-c/i-wish-i-were-the-moon.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-115427423359060192</id><published>2009-09-16T00:32:00.000-03:00</published><updated>2009-09-16T00:34:50.992-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Ejemplo de GUI Bizarra...</title><content type='html'>La siguiente captura de pantalla pertenece a un software de CMR bastante popular entre las compañías de telecomunicaciones. Pueden observar este cuadro de diálogo al finalizar el alta un cliente ADSL. Juro que no hay ningún tipo de edición sobre la imagen.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/2095/3176/1600/Vantive.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://photos1.blogger.com/blogger/2095/3176/320/Vantive.jpg" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Podría argumentarse que esta interfaz no es bizarra, sólo estúpida... pero prefiero no hacer mucho ruido al respecto.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-115427423359060192?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/115427423359060192/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=115427423359060192' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/115427423359060192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/115427423359060192'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2006/07/ejemplo-de-gui-bizarra.html' title='Ejemplo de GUI Bizarra...'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-299584701060839852</id><published>2009-09-15T12:26:00.003-03:00</published><updated>2009-09-16T00:29:59.538-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Reflexión y Opinión'/><title type='text'>Sobre el IQ</title><content type='html'>&lt;p&gt;&lt;br /&gt;Fuente: &lt;a href="http://stealthissoftware.blogspot.com/2009/03/sobre-el-iq.html"&gt;Steal This Software&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Hace rato que tenia ganas de escribir sobre esto. Cuantas veces uno ha oído "tal persona tiene tanto de IQ" o "determinado personaje posee un coeficiente intelectual de X"&lt;br /&gt;Ahora, alguna vez uno se planteó qué es un IQ??&lt;br /&gt;Según wikipedia el IQ es un resultado de un test:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;El cociente intelectual o coeficiente intelectual,[1] abreviado CI (en inglés IQ) es un número que resulta de la realización de un test estandarizado para medir las habilidades cognitivas de una persona, "inteligencia", en relación con su grupo de edad.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;La primera vez que me enteré de la existencia de esto (tendría unos 15 años) me pareció interesante, anque simplista voy a reconocer. Simplista para ser algo que "define" la inteligencia. O sea, vendría a ser, X individuo hace un test que consiste en N numero de preguntas (de logica, reconocimiento de series, patrones) y dependendiendo de como le vaya, es cuan inteligente es esa persona. Muy chato para mi gusto. Sin envargo realicé varios tests por curiosidad. No recuerdo los resultados (seguramente me salió que estoy en la media) pero lo que si recuerdo es que, siendo distintos los tests, hacer el primero me fue mas dificil que el segundo. Esto es, el hacer el primero me "entrenó" de alguna forma. Hizo que hacer el segundo fuera más sencillo, además de que sabía que esperar (a pesar de que los tests no eran iguales) me había mostrado una forma encarar ciertos problemas. Entonces, hice algunos más y noté que era como si justamente fuera un entrenamiento, practicar el tipo de ejercicios hacía que los posteriores costaran un poco menos.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;De todo esto se desprende mi conclusión. Los tests de IQ dan un número a la habilidad/experiencia de una persona para resolver un tipo de problema. La inteligencia no es algo "medible" y mucho menos por completar unas series de cuadraditos o de números. Estos tests sólo dividen, y estancan. Le dicen a alguien "vos sos la media" como que no hubiera más remedio.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;No me hubiera atrevido a publicar esta entradad (hubiera considerado que estos son disparates míos) si no fuera por un comentario que leí en un libro de Paenza (de las serie "matematica, estás ahí?") donde él mismo opinaba algo similar a mi.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-299584701060839852?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/299584701060839852/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=299584701060839852' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/299584701060839852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/299584701060839852'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/sobre-el-iq.html' title='Sobre el IQ'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-516239179960927925</id><published>2009-09-15T11:56:00.001-03:00</published><updated>2009-09-15T12:49:49.703-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Frase del día</title><content type='html'>&lt;span style="font-size:180%;"&gt;"Copiar de una fuente es plagiar, copiar de dos o más es investigar."&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-516239179960927925?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/516239179960927925/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=516239179960927925' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/516239179960927925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/516239179960927925'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/frase-del-dia.html' title='Frase del día'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-8922597137152087770</id><published>2009-09-13T21:57:00.009-03:00</published><updated>2009-09-14T14:24:48.348-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Videojuegos'/><title type='text'>A Una Década Del Ultimo Sueño de Sega</title><content type='html'>&lt;p&gt;El pasado miércoles no fue un día cualquiera para los aficionados a los consolas de videojuegos (en especial para los que llevan más de 20 años arrastrándose por este mundo). Concretamente, se cumplieron diez años desde aquél memorable 9/9/99, fecha elegida por la filial norteamericana de Sega para el lanzamiento de la esperada &lt;span style="font-weight: bold;"&gt;Dreamcast&lt;/span&gt; en occidente, la que sería luego conocida como la mejor y la última consola de videojuegos de dicha compañía.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Si tuvieron la suerte de poseer una de estas maravillas (o al menos de haberla probado en casa de algún amigo / enemigo algo más afortunado), saben de lo que estoy hablando. Juegos como Soul Calibur (considerado por muchos como el mejor juego de lucha de la historia), Sonic Adventure, Virtua Tennis, Shenmue (maravilla técnica si las hubo), Power Stone, Skies Of Arkadia y Dead Or Alive 2 representaban los desarrollos cumbre en juegos de aquél entonces.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Sega venía de tiempos muy complicados: el rotundo fracaso de la Saturn (consola de 32bit que compartió su generación con Playstation y N64) y del Sega32X (una suerte de "upgrade" para la megaexitosa Genesis/Mega Drive) dejaron en bastantes apuros económicos a la compañía nipona, que no podía darse el lujo de fracasar nuevamente. El proyecto que devolvería los laureles a Sega se conocería inicialmente como Katana, y mediante una acertada jugada se lanzaría casi un año antes que sus competidores (la Playstation 2 de Sony, la Nintendo GameCube y el Xbox de Microsoft).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Algunas de las características técnicas más destacables de la Dreamcast eran su procesador de video (PowerVR2 de Nec); los VMU (una suerte de memory card con esteroides); el modem de 56k integrado (esta consola prácticamente inventó el juego online para este tipo de plataformas); y la posibilidad de utilizar un cable D-Sub para conectarlo a un monitor VGA o HDTV (mejorando notablemente la calidad de imagen).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;El sistema de almacenamiento era el bizarro "GD-ROM", de manofactura propietaria, capaz de almacenar hasta 1GB de información. Una decisión bastante desacertada, por cierto, motivada principalmente por un intento para evitar la piratería. Por supuesto, dicho propósito no fue conseguido: los siempre hábiles piratas lograron hacer "rippings" en CD-ROMs convencionales, con algunos trucos realtivamente sencillos como eliminación de videos y resampleo de audio. Un lectora de DVD externa fue anunciada, pero lamentablemente no llegó a dar a luz.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;En fin, una máquina que en teoría lo tenía casi todo como para llevarse al mundo por delante. Y eso era lo que parecía ocurrir en principio: durante su lanzamiento, el producto se agotó rápidamente, y al poco tiempo Sega se vió en dificultades para poder cumplir con la alta demanda de Dreamcast que el mercado exigía. Los primeros juegos fueron de un éxito notable, y en general eran una mezcla de conceptos relativamente nuevos (como Sonic Adventure o Shenmue) con clásicos arcades de Sega (como Daytona Usa, Crazy Taxi y Virtua Fighter). Los títulos deportivos de la línea Sega Sports son particularmente recordados (entre ellos el mítico Virtua Tennis).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;¿Que ocurrió luego? Bueno, eso es motivo de divergente discusión, pero en general se coincide en lo siguiente: Sega no pudo destinar el dinero suficiente que un buen plan de Marketing requería, ni logró convencer a la suficiente cantidad de desarrolladores terceros de que publicaran en su consola (es particularmente llamativo el caso de Electronics Arts, que abiertamente le dió la espalda a Dreamcast. Pueden leer más acerca de esto en la referencias). Como resultado, la casa del erizo azul ya no poseía la solvencia financiera para seguir fabricando Dreamcast y sostenerla en el mercado. La ventaja inicial que había logrado sacarle a sus competidores se había esfumado, y Playstation 2 (a la que Sony estaba promocionando sin reparar en gastos de ningún tipo) comenzaba a apoderarse del mercado.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Marzo del 2001 fue el final del camino. Sega decidió centrar su antención en el desarrollo de software, abandonando el hardware definitivamente. Durante algún tiempo más, no obstante, siguieron saliendo considerables juegos nuevos, totalizando una biblioteca de bastante maś de 600 títulos. Asimismo, creció el círculo de desarrollos "homebrew" alrededor de esta consola (incluso hubo una versión del sistema GNU/Linux Debian preparada para correr en Dreamcast).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Sintetizando, Dreamcast no logró devolverle a Sega el lugar que en el pasado había alcanzado con éxitos como el Master System y el Sega Genesis, pero indudablemente no puede considerársele un fracaso. Fue un rotundo suceso comercial que, aunque breve, batió varias marcas. Dreamcast innovó en varios aspectos (como el del juego online), y definió nuevos estándares de calidad para los desarrollos de las generaciones siguientes (Soul Calibur sigue viéndose maś que bien hoy día, incluso pese a sus años). Y principalmente, brindó muchas horas de sano entretenimiento a incontables usuarios. Entre ellos se encuentra quién escribe estas líneas, en un intento de brindarle un humilde homenaje a tan formidable pieza de hardware, de una época muy destacable dentro de la historia de los videojuegos.&lt;/p&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Referencias&lt;/span&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Entrada en Wikipedia&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Dreamcast"&gt;http://en.wikipedia.org/wiki/Dreamcast&lt;/a&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Artículo conmemorativo en Gamasutra, con interesantes entrevistas a los involucrados en la producción de la consola&lt;br /&gt;&lt;a href="http://www.gamasutra.com/view/feature/4128/the_rise_and_fall_of_the_dreamcast.php?"&gt;http://www.gamasutra.com/view/feature/4128/the_rise_and_fall_of_the_dreamcast.php?&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-8922597137152087770?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/8922597137152087770/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=8922597137152087770' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8922597137152087770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/8922597137152087770'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/una-decada-del-ultimo-sueno-de-sega-el.html' title='A Una Década Del Ultimo Sueño de Sega'/><author><name>Lorenzo Chomp</name><uri>http://www.blogger.com/profile/07218735835195728089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-2133965783164469100</id><published>2009-09-10T14:33:00.002-03:00</published><updated>2009-09-10T14:38:54.868-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Análisis y Diseño'/><title type='text'>No se recomienda borrar datos</title><content type='html'>Fuente: &lt;a href="http://www.dosideas.com/base-de-datos/712-no-se-recomienda-borrar-datos.html"&gt;Dos Ideas&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;table class="contentpaneopen"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;span class="small"&gt;Escrito por Leonardo De Seta  &lt;/span&gt;       &lt;/td&gt; &lt;/tr&gt;  &lt;tr&gt;  &lt;td class="createdate" valign="top"&gt;   Miércoles 09 de Septiembre de 2009 17:43 &lt;/td&gt; &lt;/tr&gt;   &lt;tr&gt; &lt;td valign="top"&gt; &lt;p&gt;&lt;img style="width: 99px; height: 99px;" src="http://www.dosideas.com/images/stories/bases-de-datos/base-de-datos-borrar.png" alt="base de datos" align="left" hspace="10" /&gt; En las bases de datos, la eliminación lógica es aquella que ocurre al activar una marca de "eliminado" al registro, mientras que la eliminación física consiste en eliminar &lt;em&gt;realmente&lt;/em&gt; el registro de la base. ¿Cuál estrategia es mejor?&lt;/p&gt;    &lt;p&gt;Quienes aplican el borrado lógica sugieren agregar una columna "eliminado" a la tabla, y dejar los datos intactos. Una fila se considera borrada si la columna "eliminado" contiene un "true". Este enfoque es simple, facil de entender, rápido para implemente y explicar, pero a menudo se implementa mal. El problema es que, en general, eliminar una fila o entidad no es un evento simple. No sólo afecta a los datos del modelo, sino también a la &lt;em&gt;forma&lt;/em&gt; del modelo. Es por esto que existen las claves foráneas, para asegurarnos de no terminar con Items de Factura sin una Factura padre. Y este es el más sencillo de los ejemplos...&lt;/p&gt; &lt;p&gt;Cuando hay que lidiar con las bajas lógicas, es facil terminar en situaciones de corrupción de datos. Por ejemplo, el campo "última órden" del Cliente (una optimización que nadie se acordó) podría terminar apuntando a una Orden con baja lógica.&lt;/p&gt; &lt;p&gt;Entonces, si un desarrollador tiene que borrar un registro de la base, y las bajas lógicas parecen desrecomendadas, queda la opción de las bajas físicas. Para preservar la integridad de datos, deberemos eliminar la fila en cuestión y todas las filas relacionadas en cascada. Pero en el mundo real la cascada no es posible.&lt;/p&gt; &lt;p&gt;Supongamos que el departamento de marketing decide eliminar un producto del catálogo. ¿Deberían desaparecer también todas las órdenes que contienen ese producto? Y si continuamos la cascada, ¿deberíamos borrar todas las peticiones para esas órdenes también? Y siguiendo, ¿deberíamos rearmar el resumen financiero de la empresa? &lt;/p&gt; &lt;p&gt;Obviamente, no.&lt;/p&gt; &lt;p&gt;El problema viene por la interpretación del "eliminar". En el ejemplo anterior, cuando marketing dice "eliminar", se refiere a discontinuar un producto. No queremos vender más este producto. Queremos quitarlo del inventario, y no hacer más pedidos a nuestro proveedor. El producto no debería aprecer más cuando nuestros clientes hacen una búsqueda en el sitio, pero la gente del almacen va a tener que seguir gestionando este producto en el interín. Por supuesto, es mucho más facil decir "eliminar el producto" que explicar todo esto.&lt;/p&gt; &lt;p&gt;Entonces, tenemos varias interpretaciones del "eliminar" para los usuarios: &lt;/p&gt; &lt;ul&gt;&lt;li&gt;Las órdenes de compra no se borran: se cancelan. De hecho, también podría haber cargos extra por cancelar una órden tarde.&lt;/li&gt;&lt;li&gt;Los empleados no se borran: renuncian, se jubilan o se los despide. También es probable que haya que gestionar una compensación.&lt;/li&gt;&lt;li&gt;Los puestos no se borran: se cubren (cuando entra un candidato).&lt;/li&gt;&lt;li&gt;y así...&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;En todos los casos, debemos enfocarnos en la tarea que el usuario desea realizar, en vez de en acciones técnicas sobre la base de datos.&lt;/p&gt; &lt;p&gt;En vez de enfocarnos en una columna "eliminado", lo mejor es usar un campo que contenga el &lt;em&gt;estado &lt;/em&gt;del dato: activo, discontinuado, cancelado, obsoleto, etc. Estos campos de estado le permiten al usuario mirar los datos históricos y tomar decisiones.&lt;/p&gt; &lt;p&gt;La eliminacion física de datos puede tener consecuencias negativas más allá de romper la integridad. Tenemos que tener mucho cuidado cuando intentamos una eliminación física. Y como regla general, no borremos nada.&lt;/p&gt; &lt;h5&gt;Basado en &lt;a href="http://www.infoq.com/news/2009/09/Do-Not-Delete-Data"&gt;Deleting data is not a recommended practice&lt;/a&gt;.&lt;/h5&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-2133965783164469100?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/2133965783164469100/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=2133965783164469100' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2133965783164469100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/2133965783164469100'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/no-se-recomienda-borrar-datos.html' title='No se recomienda borrar datos'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-5533062049847133499</id><published>2009-09-09T14:50:00.003-03:00</published><updated>2009-09-09T15:06:07.935-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Programación Talabartera Volumen 1</title><content type='html'>Hoy: Cómo verificar que una variable sea un entero en BASH...&lt;br /&gt;&lt;br /&gt;(tomado de por ahí)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if [ $VARIABLE -eq $VARIABLE 2&gt; /dev/null ]; then&lt;br /&gt; echo "integer"&lt;br /&gt;else&lt;br /&gt; echo "not integer"&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;2)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;echo "${VAR}" | grep "[^0-9]" &gt; /dev/null &gt;&amp;amp;1&lt;br /&gt;if [ "$?" -eq "0" ]; then&lt;br /&gt; echo string&lt;br /&gt;else&lt;br /&gt; echo integer&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;3)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if [ $VARIABLE -ge 0 2&gt;/dev/null ]; then&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;4)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;echo "${VAR}" | grep -v -- "^-\?[0-9]\+$" &gt; /dev/null &gt;&amp;amp;1&lt;br /&gt;if [ "$?" -eq "0" ]; then&lt;br /&gt;  echo string&lt;br /&gt;else&lt;br /&gt;  echo integer&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;5)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if (($x)); then&lt;br /&gt; echo "true"&lt;br /&gt;else&lt;br /&gt; echo "false"&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;6)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if (($x)) 2&gt;/dev/null; then&lt;br /&gt; echo "true"&lt;br /&gt;else&lt;br /&gt; echo "false"&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;7)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if echo $VAR | grep -Eq '^[+-]?[0-9]+$'&lt;br /&gt;then&lt;br /&gt; echo integer&lt;br /&gt;else&lt;br /&gt; echo non integer&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-5533062049847133499?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/5533062049847133499/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=5533062049847133499' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5533062049847133499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5533062049847133499'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/programacion-talabartera-volumen-1.html' title='Programación Talabartera Volumen 1'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-6637174544041497781</id><published>2009-09-08T12:04:00.003-03:00</published><updated>2009-09-08T12:09:03.339-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Recreo: el diccionario del Eclipse</title><content type='html'>Hoy...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_PyuhTLDSZLs/SqZy-ivWo2I/AAAAAAAAAHA/NFqwPzzBwn8/s1600-h/sugerencia.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 320px;" src="http://1.bp.blogspot.com/_PyuhTLDSZLs/SqZy-ivWo2I/AAAAAAAAAHA/NFqwPzzBwn8/s400/sugerencia.JPG" alt="" id="BLOGGER_PHOTO_ID_5379113223743513442" border="0" /&gt;&lt;/a&gt;más de cerca...&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_PyuhTLDSZLs/SqZzMU4JuSI/AAAAAAAAAHI/xgQO7nSc9sE/s1600-h/zoom-sugerencia.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 338px; height: 287px;" src="http://3.bp.blogspot.com/_PyuhTLDSZLs/SqZzMU4JuSI/AAAAAAAAAHI/xgQO7nSc9sE/s400/zoom-sugerencia.jpg" alt="" id="BLOGGER_PHOTO_ID_5379113460540487970" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-6637174544041497781?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/6637174544041497781/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=6637174544041497781' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6637174544041497781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6637174544041497781'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/recreo-el-diccionario-del-eclipse.html' title='Recreo: el diccionario del Eclipse'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_PyuhTLDSZLs/SqZy-ivWo2I/AAAAAAAAAHA/NFqwPzzBwn8/s72-c/sugerencia.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-6550507496273197775</id><published>2009-09-07T15:30:00.003-03:00</published><updated>2009-09-08T00:09:52.355-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Análisis y Diseño'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>La felicidad del usuario según la funcionalidad del software</title><content type='html'>Anda dando vueltas por ahí...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_PyuhTLDSZLs/SqVUPqWLsyI/AAAAAAAAAGQ/PPs19Atuglc/s1600-h/featuritis-curve.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 312px;" src="http://1.bp.blogspot.com/_PyuhTLDSZLs/SqVUPqWLsyI/AAAAAAAAAGQ/PPs19Atuglc/s400/featuritis-curve.jpg" alt="" id="BLOGGER_PHOTO_ID_5378797958006027042" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-6550507496273197775?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/6550507496273197775/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=6550507496273197775' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6550507496273197775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/6550507496273197775'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/09/la-felicidad-del-usuario-segun-la.html' title='La felicidad del usuario según la funcionalidad del software'/><author><name>Héctor Francisco Hernández</name><uri>http://www.blogger.com/profile/03277695258644974663</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_PyuhTLDSZLs/SqVUPqWLsyI/AAAAAAAAAGQ/PPs19Atuglc/s72-c/featuritis-curve.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-7023427962328188820</id><published>2009-08-01T17:51:00.001-03:00</published><updated>2009-08-30T05:22:49.688-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Análisis y Diseño'/><title type='text'>Consejos para Entrevistar Usuarios</title><content type='html'>&lt;hr size="2"&gt;Copyright (c) 2009 Héctor Francisco Hernández &amp;lt;hectorfh@gmail.com&amp;gt;.&lt;br&gt;&lt;br /&gt;La copia exacta y la distribución de copias exactas de esta página son&lt;br /&gt;permitidas mundialmente en cualquier medio, provisto que esta nota se&lt;br /&gt;mantenga.&lt;hr size="2"&gt;&lt;br&gt;Mis andanzas por el mundo de la informática y la computación son de variopintas naturalezas. Estos consejos surgen de mi experiencia en el último proyecto en el que he estado involucrado. De la necesidad de hacer análisis y relevamiento y de tener que entrevistar a los futuros usuarios del nuevo sistema.&lt;br&gt;Dada mi relativamente corta trayectoria como desarrollador, era la primera vez que me encontraba haciendo este tipo de trabajo.&lt;br&gt;Afortunadamente las entrevistas fueron exitosas y muy fructíferas, ya que me aportaron valiosísima información, que no estaba disponible de otra forma, para completar mi análisis. Y además he aprendido algunas cosas que aquí les dejo.&lt;br&gt;&lt;h2&gt;Sobre el Planeamiento&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Tenga un plan:&lt;/b&gt; Lo primero y lo fundamental en una entrevista es tener un plan bien claro acerca de qué información se quiere obtener y de qué manera se va a obtener. En función de ello se deben seleccionar las preguntas cuidadosamente. Recuerde que la mayor parte de la entrevista consiste en su planeamiento y búsqueda de las preguntas adecuadas. Es ahí donde debe invertir el tiempo.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Pregunte eficazmente:&lt;/b&gt; Las preguntas no deben ser abiertas por demás, deben ser precisas y eficaces. De este modo, si es posible trate de hacer preguntas que admitan una cantidad de respuestas acotadas. En ese caso podría hasta leerle las posibles respuestas al usuario. Por ejemplo, si desea saber qué funciones del sistema actual el usuario utiliza, no le pregunte "¿Qué funciones del sistema actual utiliza?", en vez de eso pregúntele "¿Cuáles de las siguientes funciones del sistema actual utiliza?" y proceda a leerle las funciones. Esto le ayudará al usuario a no olvidarse de ninguna y a usted a obtener una respuesta previsible y manejable.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Pregunte sobre lo que el usuario sabe:&lt;/b&gt; No haga preguntas cuya respuesta el usuario desconoce, o que no es obligación que conozca. Recuerde que el usuario sabe perfectamente cómo se hace el trabajo que le toca realizar porque así se lo indicaron, pero difícilmente conozca cómo se podría mejorar o de qué otra manera se podría realizar. El usuario no ha pensado en ello porque por lo general no es su trabajo. En cambio, es buena idea que usted, que es analista, sí lo piense. Recuerde que es el médico el que hace el diagnóstico y establece el tratamiento, no el paciente.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Lo bueno, si breve, dos veces bueno:&lt;/b&gt; Trate de que la entrevista sea lo más breve posible. Hay dos razones para hacer esto, la primera es que a medida que el tiempo pasa, las ganas y la concentración de usted y el entrevistado van disminuyendo y las cosas se van volviendo más difíciles. La segunda es por una cuestión de respeto hacia el entrevistado que gentilmente y sin obligación le está cediendo su tiempo.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Durante la Entrevista&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Dirija la charla:&lt;/b&gt; Durante la entrevista usted debe dirigir la charla en todo momento, de lo contrario le dará la oportunidad al entrevistado de hacerlo y se podría entrar en divagaciones sobre asuntos irrelevantes. Esto no le será difícil si ha planeado correctamente. De este modo usted hablará como quien conoce acerca de lo que está preguntando y sabe exactamente lo que quiere. Por lo que el entrevistado no pensará que es un improvisado que está perdiendo el tiempo y se lo está haciendo perder a él también.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Escuche:&lt;/b&gt; Escuche atentamente al usuario, con la menor cantidad de prejuicios posibles, y evite dar por sabidas las respuestas&lt;br /&gt;de antemano. Muchas veces el usuario suele dar respuestas distintas a&lt;br /&gt;las que esperamos. También evite emitir juicios personales, que casi nunca vienen al caso.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Escriba durante la entrevista:&lt;/b&gt; Escriba lo que el usuario le va contando, es lo que debe hacer si no tiene una memoria privilegiada o poco ocupada en donde pueda grabar todo. Personalmente, y por una saturación (o limitación) mental, suelo olvidar lo que no he anotado.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Haga amigos:&lt;/b&gt; Aproveche la entrevista para cultivar o consolidar relaciones, es su&lt;br /&gt;oportunidad para "caer bien" y para que lo tengan presente. Los usuarios&lt;br /&gt;juegan un papel fundamental en el desarrollo de los sistemas y en el&lt;br /&gt;éxito o fracaso de sus proyectos, por lo que parte de su trabajo&lt;br /&gt;consiste en "hacer sociales". Desarrolle sus aptitudes en comunicación,&lt;br /&gt;son de vital importancia y de gran valor.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Sea agradecido:&lt;/b&gt; Es buena idea ir por la vida sonriendo y agradeciendo a Dios, pero en este caso particular recuerde que el entrevistado no tiene la obligación de colaborar con&lt;br /&gt;usted. No es él quién lo necesita, sino es usted quien lo necesita a&lt;br /&gt;él. Por lo que debe estar sumamente agradecido por el tiempo y la&lt;br /&gt;atención que le brinda y estará moralmente en deuda. También recuerde&lt;br /&gt;que esto&lt;br /&gt;es un ida y vuelta y que es buena idea devolver las atenciones.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Luego de la Entrevista&lt;/h2&gt;Luego de la entrevista es muy importante que documente las respuestas del usuario y la información obtenida. La razones para ello son a) no olvidar las respuestas, b) poder compartirlas y además c) nos servirá para cuando tengamos que rendir cuentas acerca de nuestro trabajo.&lt;br&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-7023427962328188820?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/7023427962328188820/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=7023427962328188820' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/7023427962328188820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/7023427962328188820'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/08/copyright-c-2009-hector-francisco.html' title='Consejos para Entrevistar Usuarios'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4892936280028035666</id><published>2009-06-15T22:47:00.005-03:00</published><updated>2009-09-16T00:29:59.538-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Análisis y Diseño'/><category scheme='http://www.blogger.com/atom/ns#' term='Reflexión y Opinión'/><title type='text'>¿Qué es el Software?</title><content type='html'>&lt;hr /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Copyright (c) 2009 Héctor Francisco Hernández &amp;lt;hectorfh@gmail.com&amp;gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La copia exacta y la distribución de copias exactas de esta página son permitidas mundialmente en cualquier medio, provisto que esta nota se mantenga. &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Dice un importante libro de ingeniería de software:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Muchas personas asocian el término software con los programas de computadora. De hecho, ésta es una visión muy restrictiva. El software no son sólo programas, sino todos los documentos asociados y la configuración de datos que se necesitan para hacer que estos programas operen de manera correcta. Por lo general, un sistema de software consiste de diversos programas independientes, archivos de configuración que se utilizan para ejecutar estos programas, un sistema de documentación que describe la estructura del sistema, la documentación para el usuario que explica cómo utilizar el sistema y, en cuanto a los productos de software, sitios Web que permitan a los usuarios descargar la información de productos recientes.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Claro está que asociar el término "software" con los programas de computadoras es una visión restrictiva. Sin embargo, la visión del autor acerca del término también lo es. El punto es que en ningún momento se ha incluído a las personas como parte de un sistema "software", ni a los usuarios, ni a los desarrolladores, ni a los implementadores. ¿Acaso no lo son?&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;En mi opinión, el "software" es poco más que conocimiento. Construir un sistema consiste en generar conocimiento, parte de este conocimiento se plasma en el código fuente de los programas, otra en la documentación, pero gran parte se encuentra en el cerebro de los desarrolladores y de los usuarios. Es mencionado como "conocimiento tácito", a diferencia del otro que se llama "conocimiento explícito". Mucho de este conocimiento tácito no es posible codificarlo (convertirlo en conocimiento explícito) ni transferirlo. ¿Acaso no es este conocimiento parte del sistema?&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Poseer una visión u otra cambiará las decisiones que tomemos a la hora de gestionar proyectos software. Si no consideramos a las personas como parte de él, probablemente creamos que sea posible dejar ir a un desarrollador, por ejemplo, sin perder un pedazo del sistema. Debemos prever antes de comenzar el proyecto que una parte importante de los resultados obtenidos será el conocimiento logrado por la gente que participe de él. Este conocimiento es también patrimonio de la organización (se conoce como capital intelectual) y debe ser gestionado, sería inocente ignorarlo y no actuar en consecuencia.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Resumiendo mi idea, creo que el software no se trata de programas de computadora, de manuales de usuario o de diagramas UML, sino de conocimiento. Esas son sólo algunas de las formas en las que el conocimiento puede presentarse, pero existen otras más complejas. No reconocerlas podría conducir a tomar malas decisiones.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;br /&gt;Referencias&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;a href="http://es.wikipedia.org/wiki/Gesti%C3%B3n_del_conocimiento"&gt;Artículo de la Wikipedia acerca de la Gestión del Conocimiento&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Libro "Ingeniería del Software" de Ian Sommerville&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4892936280028035666?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4892936280028035666/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4892936280028035666' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4892936280028035666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4892936280028035666'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/06/que-es-el-software.html' title='¿Qué es el Software?'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-1552916733130998858</id><published>2009-04-05T19:35:00.037-03:00</published><updated>2009-09-16T00:48:29.143-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='OLAP'/><title type='text'>Herramientas Libres para OLAP: Mondrian y JPivot</title><content type='html'>Presentación de Mondrian y JPivot, dos herramientas libres para OLAP en Java&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Copyright (c) 2009 Héctor Francisco Hernández &amp;lt;hectorfh@gmail.com&amp;gt;.&lt;br /&gt;Se otorga permiso para copiar, distribuir y/o modificar este documento bajo los términos de la Licencia de Documentación Libre de GNU, Versión 1.3 o cualquier otra versión posterior publicada por la Free Software Foundation; sin Secciones Invariantes ni Textos de Cubierta Delantera ni Textos de Cubierta Trasera. Una copia de la licencia se encuentra en http://www.gnu.org/copyleft/fdl.html.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;I. ¿Qué es OLAP?&lt;/h2&gt;OLAP suele ser el primer paso en el campo de la inteligencia de negocio (Business Intelligence) en toda organización.&lt;br /&gt;&lt;br /&gt;Repasemos brevemente el concepto de sistema transaccional con el fin de introducir OLAP.&lt;br /&gt;&lt;br /&gt;En informática, los sistemas transaccionales son aquellos que están hechos para registrar y soportar las transacciones de negocio, por ejemplo operaciones empresariales como la venta, la compra, la adquisición de créditos, el pago, entre otras.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Se suele llamar a esta clase de uso de sistemas informáticos OLTP, "On Line Transaction Processing".&lt;br /&gt;&lt;br /&gt;Estos sistemas deben estar preparados para soportar un gran número de usuarios en línea y distintos tipos de operaciones de manera concurrente. Y suelen tener la característica de que la interacción entre el usuario y el sistema es relativamente corta: menos de un segundo en muchos casos. La operación de negocio se llevará a cabo completamente a través de varias interacciones cortas que exigirán una respuesta inmediata. Además deben proveer datos actualizados hasta la última transacción; deben estar disponibles de forma continua; deben ser rápidos; y deben brindar la protección e integridad de los datos.&lt;br /&gt;&lt;br /&gt;Sin embargo el universo informático dentro de una organización no termina en las aplicaciones OLTP. Existen otras aplicaciones, generalmente destinadas a soportar la toma de decisiones, que consisten en analizar una gran cantidad de datos para generar informes de negocio de ventas, mercadotecnia, informes de dirección y áreas similares.&lt;br /&gt;&lt;br /&gt;Esta aplicación de sistemas informáticos se suele denominar OLAP, "On Line Analytical Processing".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;OLAP (online analytical processing o procesamiento analítico en línea) es un término acuñado por EF Codd &amp;amp; Associates, que publicó un libro blanco en 1993, encargado por Arbor Software (en la actualidad Hyperion Solutions), titulado "Prestación de OLAP (Procesamiento Analítico On-Line) para análisis de usuario: Un mandato de las TI".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;"En Línea" implica que aún cuando grandes cantidades de datos están involucradas en las consultas, el sistema debe responder lo suficientemente rápido como para permitir ser usado de manera interactiva.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Hay que remarcar que Codd cobró para escribir este libro blanco de apoyo a Essbase (producto comercial de Arbor). El documento de Codd fue visto como propaganda parcial.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Estos sistemas recolectan y procesan información registrada por los sistemas transaccionales de la organización y ponen los resultados a disposición del usuario a través de reportes que se generan de manera instantanea. Estos datos son utilizados generalmente para tomar decisiones y por lo general no necesitan estar actualizados al día de la fecha. Por ejemplo, el usuario requiere un informe de ventas del último cuatrimestre, o se precisa una comparación de los gastos en los últimos años.&lt;br /&gt;&lt;br /&gt;La siguiente captura de pantalla muestra un reporte OLAP clásico.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_FDA3N96YFtA/Sdl8sfDnCXI/AAAAAAAAAB4/Ql9NyWWKOZI/s1600-h/jpivot0.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5321421538407680370" src="http://4.bp.blogspot.com/_FDA3N96YFtA/Sdl8sfDnCXI/AAAAAAAAAB4/Ql9NyWWKOZI/s400/jpivot0.png" style="cursor: pointer; display: block; height: 396px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(Reporte OLAP generado con JPivot)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Bases de datos OLAP&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Aunque existen muchas herramientas de generación de informes que operan sobre las bases de datos de los sistemas transaccionales, suelen ser lentas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Los diseños de estas bases de datos están pensados para realizar altas, bajas y modificaciones de la forma más óptima, teniendo un mínimo grado de redundancia de información posible. Esto significa que se tiende a la normalización.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Sin embargo la normalización puede hacer lentas las consultas complejas, ya que al estar la información distribuida en muchas tablas es necesario calcular productos cartesianos complejos (en sql "inner join", "outer join", el operador coma) y en gran cantidad. Este tipo de operaciones es de los más costosos para el motor de base de datos.&lt;br /&gt;&lt;br /&gt;Cuando las consultas implican cruzar varias tablas de decenas o cientos de miles de registros, el sistema no responde satisfactoriamente. Además de tardar varios minutos en presentar la información, se consumen recursos haciendo más lento y degradando el servicio prestado por el sistema a los otros usuarios en línea.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La solución adoptada consiste es extraer, tranformar y cargar (ETL: Extract, Transform and Load) los datos a una base exclusiva para OLAP. Si bien las bases de datos relacionales, u orientadas a objetos en los sistemas más recientes, son las utilizadas comunmente en las aplicaciones OLTP, en el mundo OLAP las bases de datos impuestas son las multidimensionales.&lt;br /&gt;&lt;br /&gt;Conceptualmente, una base de datos multidimensional utiliza la idea de "cubos". Un cubo posee N dimensiones y en él están registrados "hechos" de un determinado tipo. Los hechos podrían ser, por ejemplo, desde las ventas realizadas por una empresa (según estudios la utilización de OLAP para el analisis de ventas es la aplicación más popular) hasta los defectos que reportan los usuarios de un sistema informático, según cuál fuese la finalidad de la aplicación.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Cada "hecho" tiene asociado un elemento de cada dimensión definida para el cubo. Por ejemplo, si el cubo registra ventas, cada venta tiene asociado un lugar geográfico (dimensión geográfica), el día en el que ocurrió (dimensión temporal), el producto que se vendió (dimensión de tipo), etc.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Además el "hecho" tiene valores asociados, por ejemplo el importe por el cual se realizó la venta o la cantidad de unidades vendidas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Poseyendo estos tres elementos, a saber, un tipo de hecho, un conjunto de dimensiones y un conjunto de valores, queda conformado un cubo capaz de responder preguntas como cuántas ventas de determinado artículo se realizaron en el mes de febrero, o cuál es el producto más vendido del trimestre pasado en la ciudad de Córdoba.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Para consultar estos datos al cubo se necesita una herramienta fundamental. Así como existen lenguajes de consultas en los otros paradigmas de bases de datos (SQL, HQL), para las bases multidimensionales el lenguaje es MDX: MultiDimensional eXpressions.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;MDX fue presentado como parte de la especificación OLE DB for OLAP (ODBO) en 1997 por Microsoft, con Mosha Pasumansky siendo uno de los arquitectos del lenguaje. Luego de la especificación siguió el lanzamiento comercial de Microsoft OLAP Services 7.0 en 1998 y más tarde Microsoft Analysis Services. La última versión de la especificación OLE DB for OLAP (ODBO) fue publicada por Microsoft en 1999.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Aunque no es un estándar, sino más bien una especificación propietaria de Microsoft, ha sido adoptada por una amplia gama de compañías en diversos productos, entre los que se incluyen Applix, Microstrategy, SAS, SAP, Whitelight, NCR, Panorama Software, Proclarity, AppSource, Cognos, Business Objects, Brio Technology, Crystal Reports, Microsoft Excel, Microsoft Reporting Services, etc.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Un ejemplo de consulta MDX es la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SELECT&lt;br /&gt; { [Measures].[Importe] } ON COLUMNS,&lt;br /&gt; { [Tiempo].[2002], [Tiempo].[2003] } ON ROWS&lt;br /&gt;FROM Ventas&lt;br /&gt;WHERE ( [Sucursal].[Zona Oeste].[Tablada] )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Esta consulta obtiene como resultado un reporte OLAP, de un aspecto similar a la captura de pantalla mostrada más arriba, con los totales de las ventas realizadas por una sucursal llamada "Tablada" de una cadena de mercados mostrando los años 2002 y 2003 en el eje vertical. No tienen mucha importancia por el momento los detalles de qué es lo que se consigue con la consulta, sólo qué aspecto tiene el lenguaje MDX. Nótese una fuerte inspiración en el lenguaje SQL, el "select-from-where".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;II. Herramientas Libres para OLAP: Mondrian y JPivot&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;Existe más de una solución OLAP en el mercado. Entre las herramientas disponibles se incluyen motores para implementar bases de datos multidimensionales nativas (solución MOLAP) o para emularlas sobre una implementación relacional (solución ROLAP), diseñadores de cubos, navegadores, generadores de reportes, graficadores, programas para realizar la extracción, transformación y carga de datos (ETL) desde bases transaccionales.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La mayoría de estas herramientas son privativas y requieren de la adquisición de una licencia para poder usarlas. Sin embargo ya comienzan a haber productos libres y de calidad aceptable que podemos utilizar en un entorno de producción. Entre estos hablaremos de dos para JEE que se pueden descargar de la internet: Mondrian, un motor ROLAP, y JPivot un explorador OLAP web basado en Mondrian que muestra la información en tablas interactivas que el usuario puede navegar.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Mondrian&lt;/h3&gt;&lt;br /&gt;La última versión de Mondrian y su documentación se encuentra en &lt;a href="http://mondrian.pentaho.org/"&gt;http://mondrian.pentaho.org/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;De una manera similar a un ORM (por ejemplo Hibernate en Java), que permite emular una base de datos orientada a objetos a partir de una relacional, Mondrian nos permite emular una base multidimensional. Permitiéndonos así realizar consultas en lenguaje MDX, pensando en términos de cubos, hechos, dimensiones y valores en lugar de tablas, registros y campos.&lt;br /&gt;&lt;br /&gt;Mondrian está compuesto por un conjunto de archivos "jar", que proveen una API inspirada en JDBC pero diseñada para trabajar con una base multidimensional. El sistema necesita que escribamos en un archivo "xml" cómo se corresponden los elementos de esta base con la base relacional.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La base relacional debe ser diseñada cuidadosamente de modo que sobre ella se pueda hacer el mapeo. Las estructuras comunmente usadas son tres:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;br /&gt;Una única tabla para el cubo donde existe un registro por cada hecho (por ejemplo, un registro por cada venta). El registro tendrá un código único, un campo o más por cada dimensión y un campo por cada valor del hecho (un campo con el importe de la venta, otro con la cantidad de artículos vendidos, etc.).&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Una estructura de estrella. Con una tabla central de hechos donde está el código único del mismo y los valores correspondientes, y varias tablas periféricas, una por cada dimensión. Los registros de la tabla central se relacionan con los registros de las tablas periféricas de un modo "muchos a uno", por lo tanto la tabla central posee además una clave foránea por dimensión.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_FDA3N96YFtA/Sdl87_oO50I/AAAAAAAAACA/Pm2clUSPHvk/s1600-h/estrella.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5321421804849260354" src="http://1.bp.blogspot.com/_FDA3N96YFtA/Sdl87_oO50I/AAAAAAAAACA/Pm2clUSPHvk/s400/estrella.png" style="cursor: pointer; display: block; height: 312px; margin: 0px auto 10px; text-align: center; width: 380px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;br /&gt;Una estructura de copo de nieve. No muy alejada de la estrella, pero busca quitar relaciones de la tabla central para ahorrar espacio.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_FDA3N96YFtA/Sdl9IatBdlI/AAAAAAAAACI/PwYgTA9CP1o/s1600-h/copo-de-nieve.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5321422018275538514" src="http://2.bp.blogspot.com/_FDA3N96YFtA/Sdl9IatBdlI/AAAAAAAAACI/PwYgTA9CP1o/s400/copo-de-nieve.png" style="cursor: pointer; display: block; height: 302px; margin: 0px auto 10px; text-align: center; width: 380px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;Para mostrar un ejemplo de mapeo, supongamos un cubo llamado "Ventas" que posee todas las ventas de una pequeña cadena de mercados. Este cubo tendrá tres dimensiones: "Rubro", "Sucursal" y "Tiempo", y también un valor, el "Importe" de la venta. Previamente crearíamos una base de datos en algún servidor que tenga conectividad con JDBC, por ejemplo MySQL. Nuestra arquitectura será la típica estrella, con la tabla de hechos "venta" y una tabla adicional por cada dimensión.&lt;br /&gt;&lt;br /&gt;Así las sentencias que crearán la base serán las siguientes:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;create database olapmercado;&lt;br /&gt;create table venta (id integer primary key, rubro_id integer,&lt;/pre&gt;&lt;pre&gt;        sucursal_id integer, tiempo_id integer, importe double);&lt;br /&gt;create table rubro (id integer primary key, nombre char(20));&lt;br /&gt;create table sucursal (id integer primary key, nombre char(20));&lt;br /&gt;create table tiempo (id integer primary key, anio integer, mes integer);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Estas tablas deben ser llenadas. Probablemente queramos hacerlo con datos que se encuentran en algún otro sistema. Por eso debemos crear un script o programita que extraiga, transforme y cargue los datos (ETL), y que lo haga periodicamente, por ejemplo todas las semanas o todos los meses.&lt;br /&gt;&lt;br /&gt;Para mapear el cubo con la tabla, creamos un archivo llamado "olapmercado.xml" con el siguiente contenido:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;Schema name="olapmercado"&amp;gt;&lt;br /&gt;  &amp;lt;Dimension name="Rubro"&amp;gt;&lt;br /&gt;    &amp;lt;Hierarchy hasAll="true" allMemberName="Todos"&lt;/pre&gt;&lt;pre&gt;        primaryKey="id"&amp;gt;&lt;br /&gt;      &amp;lt;Table name="rubro"/&amp;gt;&lt;br /&gt;      &amp;lt;Level name="Rubro" column="nombre"/&amp;gt;&lt;br /&gt;    &amp;lt;/Hierarchy&amp;gt;&lt;br /&gt;  &amp;lt;/Dimension&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;Dimension name="Sucursal"&amp;gt;&lt;br /&gt;    &amp;lt;Hierarchy hasAll="true" allMemberName="Todas"&lt;/pre&gt;&lt;pre&gt;        primaryKey="id"&amp;gt;&lt;br /&gt;      &amp;lt;Table name="sucursal"/&amp;gt;&lt;br /&gt;      &amp;lt;Level name="Sucursal" column="nombre"/&amp;gt;&lt;br /&gt;    &amp;lt;/Hierarchy&amp;gt;&lt;br /&gt;  &amp;lt;/Dimension&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;Dimension name="Tiempo"&amp;gt;&lt;br /&gt;    &amp;lt;Hierarchy hasAll="true" allMemberName="Total"&lt;/pre&gt;&lt;pre&gt;        primaryKey="id"&amp;gt;&lt;br /&gt;      &amp;lt;Table name="tiempo"/&amp;gt;&lt;br /&gt;      &amp;lt;Level name="Anio" column="anio"/&amp;gt;&lt;br /&gt;      &amp;lt;Level name="Mes" column="mes"/&amp;gt;&lt;br /&gt;    &amp;lt;/Hierarchy&amp;gt;&lt;br /&gt;  &amp;lt;/Dimension&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;Cube name="Ventas"&amp;gt;&lt;br /&gt;    &amp;lt;Table name="venta"/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;DimensionUsage name="Rubro" source="Rubro"&lt;/pre&gt;&lt;pre&gt;        foreignKey="rubro_id"/&amp;gt;&lt;br /&gt;    &amp;lt;DimensionUsage name="Sucursal" source="Sucursal"&lt;/pre&gt;&lt;pre&gt;        foreignKey="sucursal_id"/&amp;gt;&lt;br /&gt;    &amp;lt;DimensionUsage name="Tiempo" source="Tiempo"&lt;/pre&gt;&lt;pre&gt;        foreignKey="tiempo_id"/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;Measure name="Importe" column="importe"&lt;/pre&gt;&lt;pre&gt;        aggregator="sum" formatString="#,##0.00"/&amp;gt;&lt;br /&gt;  &amp;lt;/Cube&amp;gt;&lt;br /&gt;&amp;lt;/Schema&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Una vez hecho esto, ya estamos en condiciones de poder utilizar la API de Mondrian, basada en JDBC, para conectarnos a la base, ejecutar consultas MDX y obtener resultados.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Esta API tiene un aspecto similar al siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Connection connection = DriverManager.getConnection(&lt;br /&gt;  "Provider=mondrian;" +&lt;br /&gt;  "Jdbc=jdbc:mysql://localhost/olapmercado?" +&lt;/pre&gt;&lt;pre&gt;  "user=root&amp;amp;password=root1;" +&lt;br /&gt;  "Catalog=olapmercado.xml;",&lt;br /&gt;  null,&lt;br /&gt;  false);&lt;br /&gt;&lt;br /&gt;String mdxString = "select {(Sucursal, Rubro)} on rows, " +&lt;br /&gt;  "{Tiempo} on columns from Ventas";&lt;br /&gt;&lt;br /&gt;Query query = connection.parseQuery(mdxString);&lt;br /&gt;&lt;br /&gt;Result result = connection.execute(query);&lt;br /&gt;&lt;br /&gt;int[] coord = {0, 0};&lt;br /&gt;Cell cell = result.getCell(coord);&lt;br /&gt;&lt;br /&gt;etc...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pero no diré más sobre el asunto. No es preciso utilizar esta API habiendo navegadores OLAP como JPivot que pueden ejecutar la consulta y mostrar los datos en pantalla sin necesidad de programar nada.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;JPivot&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;La aplicación de Mondrian por sí misma parece estar destinada a la programación en un bajo nivel. Debemos ejecutar varios métodos de Java para establecer la conexión con la base, ejecutar la consulta y obtener los resultados, para después programar cientos de líneas según lo que necesitemos: mostrarlos en pantalla, pasarlos a alguna hoja de cálculo, imprimirlos o hacer algún gráfico.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Afortunadamente existen componentes y programas conocidos como "clientes OLAP", que trabajan con Mondrian, cuyo objetivo es proporcionar una interfaz ("front" en inglés) "prefabricada" donde, con sólo introducir la consulta MDX, se puede obtener los datos en una tabla navegable, imprimirlos, graficarlos y hasta exportarlos a una hoja de cálculo. Entre estos programas se encuentra JRubik, una aplicación de escritorio programada con Swing, y JPivot, que está implementada como un conjunto de tags JSP (tecnología web), por lo que es altamente configurable y se integra bien con nuestras aplicaciones web.&lt;br /&gt;&lt;br /&gt;JPivot se puede descargar de la página del proyecto en SourceForge, &lt;a href="http://jpivot.sourceforge.net/"&gt;http://jpivot.sourceforge.net/&lt;/a&gt;. La distribución binaria incluye el archivo ".war" listo para ser colocado en algún servidor JEE y funcionar.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Por defecto, en la distribución ya vienen algunas consultas hechas a modo de ejemplo. Se encuentran  dentro de los archivos ".jsp" en el directorio "WEB-INF/queries". En los mismos archivos se puede ver cómo se configura la cadena de conexión con la base de datos. Y en el mismo directorio se halla un archivo ".xml" de mapeo para el Mondrian (recuérdese que JPivot utiliza Mondrian y que ya viene con los ".jar" incluídos).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Los pasos para tener JPivot andando son pocos, aunque pueden llevar algunas horitas la primera vez. Primero, descargar algún servidor web como Tomcat e instalar el ".war". Segundo, armar el archivo de mapeo para el Mondrian. El paso cero habría sido tener una base de datos ya armada. Tercero, armar los archivos con las consultas MDX y la cadena de conexión (en lugar de utilizar una cadena de conexión, también es posible especificar un "datasource"), para ello tomar como base los ejemplos que vienen. Si todo va bien ya tendrémos el navegador OLAP funcionando.&lt;br /&gt;&lt;br /&gt;Luego JPivot se puede modificar según nuestras necesidades. Es fácil cambiar el aspecto de la interfaz del navegador.&lt;br /&gt;&lt;br /&gt;Suponiendo el ejemplo de más arriba, del cubo "Ventas" de la cadena de mercados, con el mismo archivo de mapeo, veamos algunas capturas de pantallas:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;br /&gt;select {(Sucursal, Rubro)} on rows, {Tiempo} on columns from Ventas&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_FDA3N96YFtA/Sdl7-Sq-3FI/AAAAAAAAABg/Ta-fZ63LHNs/s1600-h/sucursal-rubro-tiempo.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5321420744809176146" src="http://3.bp.blogspot.com/_FDA3N96YFtA/Sdl7-Sq-3FI/AAAAAAAAABg/Ta-fZ63LHNs/s400/sucursal-rubro-tiempo.png" style="cursor: pointer; display: block; height: 280px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;br /&gt;select {Sucursal} on rows, {Rubro} on columns from Ventas&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_FDA3N96YFtA/Sdl8HMwuX8I/AAAAAAAAABo/LM2Yi5k3548/s1600-h/sucursal-rubro.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5321420897841471426" src="http://2.bp.blogspot.com/_FDA3N96YFtA/Sdl8HMwuX8I/AAAAAAAAABo/LM2Yi5k3548/s400/sucursal-rubro.png" style="cursor: pointer; display: block; height: 147px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;br /&gt;select {(Rubro, Sucursal)} on rows, {Tiempo} on columns from Ventas&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_FDA3N96YFtA/Sdl8QkpQQKI/AAAAAAAAABw/e-0iy0wrvGM/s1600-h/rubro-sucursal-tiempo.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5321421058871410850" src="http://2.bp.blogspot.com/_FDA3N96YFtA/Sdl8QkpQQKI/AAAAAAAAABw/e-0iy0wrvGM/s400/rubro-sucursal-tiempo.png" style="cursor: pointer; display: block; height: 278px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Hasta aquí Mondrian y JPivot, dos herramientas para OLAP libres. Si le ha interesado le sugiero que continue leyendo la documentación de Mondrian y JPivot en sus respectivos sitios y que se anime a experimentar instalando JPivot.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;III. Referencias&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;br /&gt;Wikipedia&lt;br /&gt;&lt;a href="http://wikipedia.org/"&gt;http://wikipedia.org/&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;estadistico.com&lt;br /&gt;&lt;a href="http://www.estadistico.com/"&gt;http://www.estadistico.com/&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;SearchOracle.com&lt;br /&gt;&lt;a href="http://searchoracle.com/"&gt;http://searchoracle.com/&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;Mondrian&lt;br /&gt;&lt;a href="http://mondrian.pentaho.org/"&gt;http://mondrian.pentaho.org/&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;JPivot&lt;br /&gt;&lt;a href="http://jpivot.sourceforge.net/"&gt;http://jpivot.sourceforge.net/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-1552916733130998858?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/1552916733130998858/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=1552916733130998858' title='4 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1552916733130998858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1552916733130998858'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/04/olap.html' title='Herramientas Libres para OLAP: Mondrian y JPivot'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_FDA3N96YFtA/Sdl8sfDnCXI/AAAAAAAAAB4/Ql9NyWWKOZI/s72-c/jpivot0.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-5134365655508697160</id><published>2009-03-24T02:38:00.028-03:00</published><updated>2010-02-17T02:35:51.280-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><title type='text'>Presentación del sed</title><content type='html'>Tutorial, Guía o Simplemente Introducción al Comando Sed de Unix&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Copyright (c) 2009 Héctor Francisco Hernández &amp;lt;hectorfh@gmail.com&amp;gt;.&lt;br /&gt;&lt;br /&gt;Se otorga permiso para copiar, distribuir y/o modificar este documento bajo los términos de la Licencia de Documentación Libre de GNU, Versión 1.3 o cualquier otra versión posterior publicada por la Free Software Foundation; sin Secciones Invariantes ni Textos de Cubierta Delantera ni Textos de Cubierta Trasera. Una copia de la licencia se encuentra en http://www.gnu.org/copyleft/fdl.html.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;1. Introducción&lt;/h2&gt;&lt;br /&gt;La herramienta de Unix "sed" ("stream editor" o "editor de flujo") es, junto con "awk" (y sin&lt;br /&gt;contar a Perl, la panacea, en la contienda), la más poderosa en lo que&lt;br /&gt;a procesamiento de texto plano se refiere.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Al igual que el editor "ed", del cual toma todos sus comandos, permite escribir pequeños scripts de edición de texto en un&lt;br /&gt;particular lenguaje:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# el comando "i" inserta texto en la línea&lt;br /&gt;# que se le indique&lt;br /&gt;sed '7i hola mundo' zaraza.txt&lt;br /&gt;&lt;br /&gt;# el comando "d" borra líneas&lt;br /&gt;sed '1d' zaraza.txt&lt;br /&gt;&lt;br /&gt;# el comando "s" sustituye texto utilizando&lt;br /&gt;# expresiones regulares si se desea&lt;br /&gt;sed '1,$s/palavra/palabra/g' zaraza.txt&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sin embargo, su característica distintiva es la habilidad de procesar&lt;br /&gt;texto proveniente desde la entrada estándar. La que lo convierte en una&lt;br /&gt;herramienta ideal para construir filtros y utilizarlos en nuestros scripts&lt;br /&gt;Bourne, Korn, tcsh, bash, o lo que fuere.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2. Uso Básico&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Las instrucciones que entiende "sed" están compuestas primero por el&lt;br /&gt;número o rango de líneas sobre el cual se realizará la transformación y&lt;br /&gt;luego por la acción a realizar. Omitir el número o rango de líneas&lt;br /&gt;implicará que la acción se ejecute sobre la totalidad de las mismas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;De este modo si, por ejemplo, disponemos del siguiente listado obtenido por el&lt;br /&gt;comando "ps":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; PID   TTY TIME     CMD&lt;br /&gt;6245 pts/1 00:00:00 bash&lt;br /&gt;6246 pts/1 00:00:00 ps&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y para procesar el listado queremos suprimir los títulos,&lt;br /&gt;podríamos eliminar la primera línea con la instrucción&lt;br /&gt;"1d". Por lo tanto nuestro comando en el shell sería&lt;br /&gt;"ps | sed '1d'" y obtendríamos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;6245 pts/1 00:00:00 bash&lt;br /&gt;6246 pts/1 00:00:00 ps&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Los rangos de líneas son de la forma "n,m" que significa&lt;br /&gt;"desde la línea n inclusive hasta la línea m".&lt;br /&gt;Pudiendo "m" ser el símbolo especial "$" que&lt;br /&gt;indica el final del archivo.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Así, por ejemplo, si quisiéramos, como generalmente ocurre,&lt;br /&gt;obtener desde la línea 74 hasta la 83 de un archivo de texto denominado&lt;br /&gt;"xxx" podríamos hacerlo con la instrucción&lt;br /&gt;"74,83p" así:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sed -n '74,83p' xxx&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En este ejemplo debo hacer notar el parámetro "-n". Por&lt;br /&gt;defecto "sed" imprime todo a la salida estándar, sólo&lt;br /&gt;que "-n" modifica este comportamiento para que no lo haga. Por lo&lt;br /&gt;tanto, si no usáramos el parámetro "-n"&lt;br /&gt;obtendríamos todo el archivo "xxx" con las&lt;br /&gt;líneas desde la 74 hasta la 83 duplicadas, ya que la instrucción&lt;br /&gt;"p" volvería a imprimirlas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;No sólo es posible indicar un número de línea o un rango numérico,&lt;br /&gt;también es posible indicar una expresión regular o un rango de&lt;br /&gt;expresiones regulares.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Cuando queremos que la acción se ejecute sobre las líneas que&lt;br /&gt;coincidan con una expresión determinada, debemos escribirla delante del&lt;br /&gt;comando entre barras:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;# imprime sólo las líneas que tengan la&lt;br /&gt;# palabra "proc", lo mismo que haría el&lt;br /&gt;# comando "grep proc"&lt;br /&gt;sed -n '/proc/p'&lt;br /&gt;&lt;br /&gt;# borra lo que se encuentre entre&lt;br /&gt;# "#ifdef __WIN32__" y "#endif"&lt;br /&gt;sed '/#ifdef __WIN32__/,/#endif/d'&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;De este modo, por ejemplo, si disponemos del siguiente listado arrojado por&lt;br /&gt;"ls":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;total 888&lt;br /&gt;-rw-r--r--  1 usuario1 users   2737 2003-04-01 04:36 LICENSE.txt&lt;br /&gt;-rw-r--r--  1 usuario1 users   3639 2003-04-01 04:36 README.txt&lt;br /&gt;drwxr-xr-x  4 usuario1 users   4096 2007-09-08 21:52 build&lt;br /&gt;drwxr-xr-x  2 usuario1 users   4096 2007-09-08 21:52 convert&lt;br /&gt;drwxr-xr-x  5 usuario1 users   4096 2007-09-08 21:52 docs&lt;br /&gt;drwxr-xr-x 12 usuario1 users   4096 2007-09-08 21:52 examples&lt;br /&gt;drwxr-xr-x  3 usuario1 users   4096 2003-04-01 04:35 src&lt;br /&gt;drwxr-xr-x 12 usuario1 users   4096 2003-04-01 04:36 test&lt;br /&gt;-rw-r--r--  1 usuario1 users 351405 2003-04-01 04:36 velocity-1.3.1.jar&lt;br /&gt;-rw-r--r--  1 usuario1 users 510105 2003-04-01 04:36 velocity-dep-1.3.1.jar&lt;br /&gt;drwxr-xr-x  5 usuario1 users   4096 2007-09-08 21:52 xdocs&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y queremos obtener un listado sólo de los directorios (las filas que&lt;br /&gt;comienzan con la letra "d"). Podríamos utilizar el sed para&lt;br /&gt;borrar las entradas que no comienzan con esa letra:&lt;br /&gt;"ls -l | sed '/^d/!d'":&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;drwxr-xr-x  4 usuario1 users 4096 2007-09-08 21:52 build&lt;br /&gt;drwxr-xr-x  2 usuario1 users 4096 2007-09-08 21:52 convert&lt;br /&gt;drwxr-xr-x  5 usuario1 users 4096 2007-09-08 21:52 docs&lt;br /&gt;drwxr-xr-x 12 usuario1 users 4096 2007-09-08 21:52 examples&lt;br /&gt;drwxr-xr-x  3 usuario1 users 4096 2003-04-01 04:35 src&lt;br /&gt;drwxr-xr-x 12 usuario1 users 4096 2003-04-01 04:36 test&lt;br /&gt;drwxr-xr-x  5 usuario1 users 4096 2007-09-08 21:52 xdocs&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note que el símbolo de exclamación "!" detrás&lt;br /&gt;de la expresión regular niega la condición. Esto debería&lt;br /&gt;leerse como "borre todas las líneas que no comiencen con la letra&lt;br /&gt;d".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Otra forma de obtener el mismo resultado es imprimiendo sólo&lt;br /&gt;las líneas que comienzan con la letra "d":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ls -l | sed -n '/^d/p'&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Explicar las expresiones regulares va más allá de los&lt;br /&gt;límites de este artículo, pero el carácter "^"&lt;br /&gt;significa "comienzo de línea", por lo tanto "^d"&lt;br /&gt;hace referencia a las líneas que poseen una "d" seguida de&lt;br /&gt;su comienzo.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;3. Lo Más Importante: El Comando "s"&lt;/h2&gt;&lt;br /&gt;El comando "s" sustituye expresiones regulares en la línea actual.&lt;br /&gt;Este comando por sí sólo sería justificación para&lt;br /&gt;la existencia del sed.&lt;br /&gt;&lt;br /&gt;El modo de uso de este comando es "s/patrón/reemplazo/flags". Donde&lt;br /&gt;"patrón" es la expresión regular que debe sustituirse por&lt;br /&gt;"reemplazo" y los flags son modificadores opcionales que indican, por ejemplo,&lt;br /&gt;si la búsqueda debe discriminar entre mayúsculas y&lt;br /&gt;minúsculas o no.&lt;br /&gt;&lt;br /&gt;Siguiendo mi uso de explicar con ejemplos, suponga que posee un texto donde&lt;br /&gt;las palabras podrían estar separadas por más de un espacio:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Aquí   me pongo a   cantar&lt;br /&gt;al  compás de    la vigüela,&lt;br /&gt;que al hombre  que lo desvela&lt;br /&gt;una   pena     estrordinaria,&lt;br /&gt;como la ave solitaria&lt;br /&gt;con    el cantar se   consuela.&lt;/pre&gt;&lt;br /&gt;Sin embargo usted necesita, por alguna extraña razón que ahora no&lt;br /&gt;se me ocurre, que estén separadas por exactamente un único&lt;br /&gt;espacio. Podría sustituir el patrón "uno o más espacios"&lt;br /&gt;por un único espacio. El comando sería:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sed 's/ \+/ /g'&lt;/pre&gt;&lt;br /&gt;El "\+" luego de un carácter significa una o más ocurrencias de&lt;br /&gt;ese carácter (se recomienda leer sobre expresiones regulares en general).&lt;br /&gt;La letra "g" al final es un flag que hace que se sustituyan todos los patrones&lt;br /&gt;encontrados en cada línea. Sin él sólo se&lt;br /&gt;sustituirá la primera ocurrencia en cada renglón del texto.&lt;br /&gt;&lt;br /&gt;El resultado:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Aquí me pongo a cantar&lt;br /&gt;al compás de la vigüela,&lt;br /&gt;que al hombre que lo desvela&lt;br /&gt;una pena estrordinaria,&lt;br /&gt;como la ave solitaria&lt;br /&gt;con el cantar se consuela.&lt;/pre&gt;&lt;br /&gt;Y así también es posible hacer referencia al "patrón" o a&lt;br /&gt;"subpatrones" en el "reemplazo" mediante los carácteres especiales&lt;br /&gt;"\&amp;amp;" y "\1", "\2", "\3"... "\n" respectivamente. Por ejemplo, suponga que&lt;br /&gt;posee la siguiente lista en la que cada elemento es de la forma&lt;br /&gt;"archivo@direcorio":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;libhardware.a@dosbox-0.70/src/hardware&lt;br /&gt;Makefile.in@dosbox-0.70/src/libs&lt;br /&gt;video.h@dosbox-0.70/include&lt;br /&gt;README.video@dosbox-0.70/docs&lt;br /&gt;Makefile@dosbox-0.70/visualc_net&lt;/pre&gt;&lt;br /&gt;Luego de aplicarle a la lista "sed 's_\(.*\)@\(.*\)_\2/\1_'", obtenemos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;dosbox-0.70/src/hardware/libhardware.a&lt;br /&gt;dosbox-0.70/src/libs/Makefile.in&lt;br /&gt;dosbox-0.70/include/video.h&lt;br /&gt;dosbox-0.70/docs/README.video&lt;br /&gt;dosbox-0.70/visualc_net/Makefile&lt;/pre&gt;&lt;br /&gt;Esto significa que "\1" hace referencia al subpatrón que se encuentra&lt;br /&gt;entre los primeros paréntesis y que "\2" hace referencia al&lt;br /&gt;subpatrón entre los segundos paréntesis. Fíjese&lt;br /&gt;también que en lugar de separar los parámetros del comando con&lt;br /&gt;una barra "/" lo hice con "_". Esto es porque sed nos permite utilizar cualquier&lt;br /&gt;carácter como separador y se dará cuenta automáticamente&lt;br /&gt;de cuál estamos usando.&lt;br /&gt;&lt;br /&gt;Aunque el ejemplo que acabo de enseñar parece estúpido,&lt;br /&gt;créame que es real y que para un trabajo me ha tocado hacer un script&lt;br /&gt;que leía una lista con esa estructura.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;4. Procesando Varias Líneas por Vez&lt;/h2&gt;&lt;br /&gt;Hasta el momento en todos los ejemplos que mostré se leía una&lt;br /&gt;línea, se chequeaba una condición y se realizaba una&lt;br /&gt;operación. Y así cada operación involucraba una&lt;br /&gt;única línea.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Existen, sin embargo, circunstancias en las que es necesario operar sobre&lt;br /&gt;más de una línea por vez. Observe el siguiente archivo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Registro: 1&lt;br /&gt;Nombre: Anibal&lt;br /&gt;Telefono: 621-229&lt;br /&gt;&lt;br /&gt;Registro: 2&lt;br /&gt;Nombre: Hector&lt;br /&gt;Telefono: 562-245&lt;br /&gt;&lt;br /&gt;Registro: 3&lt;br /&gt;Nombre: Pablo&lt;br /&gt;Telefono: 622-354&lt;/pre&gt;&lt;br /&gt;Alguien ha decidido guardar una lista de personas con sus números&lt;br /&gt;de teléfonos en un extraño formato, utilizando cuatro&lt;br /&gt;líneas por registro.&lt;br /&gt;Nuestra tarea es poner la información en una manera más&lt;br /&gt;conveniente para su procesamiento:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;1;Anibal;621-229&lt;br /&gt;2;Hector;562-245&lt;br /&gt;3;Pablo;622-354&lt;/pre&gt;&lt;br /&gt;Claro está que sería imposible&lt;br /&gt;solucionar este problema leyendo de a una línea a la vez. Sería&lt;br /&gt;bueno poder trabajar leyendo de a un registro (cuatro líneas) por&lt;br /&gt;iteración.&lt;br /&gt;&lt;br /&gt;Este tipo de problemas se resuelve con el comando "N", que fuerza&lt;br /&gt;la lectura&lt;br /&gt;de la siguiente línea en la iteración actual.&lt;br /&gt;&lt;br /&gt;Al comenzar la iteración, sed trae la línea al buffer.&lt;br /&gt;Internamente el valor del buffer sería:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;buffer = "Registro: 1"&lt;/pre&gt;&lt;br /&gt;Luego de ejecutar la instrucción "N", que lee la&lt;br /&gt;línea siguiente y la concatena en el buffer, quedaría:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;buffer = "Registro: 1\nNombre: Anibal"&lt;/pre&gt;&lt;br /&gt;Observe que "\n" significa "nueva línea"&lt;br /&gt;(el carácter ASCII número 10).&lt;br /&gt;&lt;br /&gt;Como vemos, nos vamos aproximando a la solución. Basta con leer&lt;br /&gt;dos líneas más y ya tenemos el registro completo.&lt;br /&gt;Y luego de hacerlo debemos reemplazar el retorno de carro "\n"&lt;br /&gt;por ";" con "s/\n/;/g", para así llegar a:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;buffer = "Registro: 1;Nombre: Anibal;Telefono: 621-229;"&lt;/pre&gt;&lt;br /&gt;Ahora resta quitar lo que molesta, las palabras&lt;br /&gt;"Registro: ", "Nombre: ", "Telefono: " y el&lt;br /&gt;punto y coma de más al final.&lt;br /&gt;&lt;br /&gt;Para lograrlo utilizaremos una super sustitución con expresiones&lt;br /&gt;regulares:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;"s/^Registro: \(.*\);Nombre: \(.*\);Telefono: \(.*\);$/\1;\2;\3/"&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;buffer = "1;Anibal;621-229"&lt;/pre&gt;&lt;br /&gt;Ahora podríamos poner todo junto.&lt;br /&gt;Suponiendo que los datos originales estaban en el archivo "agenda",&lt;br /&gt;nuestro comando quedaría:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sed 'N;N;N;s/\n/;/g;s/^Registro: \(.*\);Nombre: \(.*\);Telefono: \(.*\);$/\1;\2;\3/' agenda&lt;/pre&gt;&lt;br /&gt;Ilegible, ¿verdad? Si así lo considera, puede hacerlo en dos&lt;br /&gt;pasos invocando dos veces al sed.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;5. Programación en Sed&lt;/h2&gt;&lt;br /&gt;En la documentación del sed de GNU, el capítulo que explica esto dice&lt;br /&gt;"Comandos para gurúes del sed ... En la mayoría de los casos, el uso de&lt;br /&gt;estos comandos indican que probablemente sea mejor programar en awk o Perl".&lt;br /&gt;La razón por la cual enseño estos comandos es para mostrar el límite de la herramienta.&lt;br /&gt;&lt;br /&gt;A pesar de no tener variables ni poseer forma de controlar el flujo de&lt;br /&gt;ejecución más que con etiquetas, un comando para "GOTO" y otro&lt;br /&gt;para "GOTO" condicional, sed es un lenguaje "Turing-completo". Esto es que&lt;br /&gt;tiene un poder computacional equivalente a la máquina universal de&lt;br /&gt;Turing. Por eso circula un mito nerd de que en algún lugar de la web&lt;br /&gt;se puede descargar los fuentes de un sokoban, un arkanoid y algún otro&lt;br /&gt;juego clásico implementado en sed.&lt;br /&gt;&lt;br /&gt;Los comandos para hacer un "GOTO" incondicional y condicional son "b" y "t"&lt;br /&gt;respectivamente. Las etiquetas se definen con el comando ":". Además&lt;br /&gt;sed posee un buffer denominado "hold space" que provee un espacio adicional para&lt;br /&gt;almacenar datos sobre el cual podremos guardar y recuperar lo que pongamos con&lt;br /&gt;los comandos h, H, g, G, x. Refiéranse a la documentación del sed&lt;br /&gt;los interesados, pues no tengo interés en explicar sobre este asunto.&lt;br /&gt;&lt;br /&gt;Imaginese que sin variables, sin estructuras de control y sin operadores&lt;br /&gt;aritméticos entre otras cosas,&lt;br /&gt;la programación en sed no es más que otro aburrido juego de&lt;br /&gt;ingenio para simios. Por este motivo será que finalizaré este&lt;br /&gt;capítulo copiándole un script del tutorial "Sed - An Introduction and&lt;br /&gt;Tutorial" de Bruce Barnett que ilustra algo de esto y dejaré el tema&lt;br /&gt;allí mismo.&lt;br /&gt;&lt;br /&gt;Lo que hace el ejemplo es guardar los párrafos en el "hold buffer" a&lt;br /&gt;medida que los va leyendo. Si el párrafo posee el patrón pasado&lt;br /&gt;por parámetro al script lo imprime.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#!/bin/sh&lt;br /&gt;sed -n '&lt;br /&gt;# Si es una línea vacía, finaliza el párrafo.&lt;br /&gt;# Por lo tanto se debe analizar. Se hace un "GOTO" a "para".&lt;br /&gt;/^$/ b para&lt;br /&gt;# Si la línea no está vacía, se agrega al "hold buffer".&lt;br /&gt;H&lt;br /&gt;# Al final del archivo se analiza el último párrafo.&lt;br /&gt;# "GOTO" a "para".&lt;br /&gt;$ b para&lt;br /&gt;# Se hace un "GOTO" al final del script.&lt;br /&gt;b&lt;br /&gt;# La etiqueta "para". Sección donde se analiza el párrafo.&lt;br /&gt;:para&lt;br /&gt;# Se recupera el párrafo completo.&lt;br /&gt;x&lt;br /&gt;# Se busca el patrón, si se encuetra se imprime el párrafo.&lt;br /&gt;/'$1'/ p&lt;br /&gt;'&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;6. Apéndice A: Quitando Tags XML. El Criterio "The Longest Match"&lt;/h2&gt;&lt;br /&gt;Para mostrar cómo se hace haré el siguiente ejercicio. Suponga&lt;br /&gt;el siguiente código HTML:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;h2&gt;&lt;br /&gt;Contenido&lt;/h2&gt;&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;li class="toclevel-1"&gt;1 &lt;span class="toctext"&gt;Historia&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li class="toclevel-1"&gt;2 &lt;span class="toctext"&gt;Ventajas del XML&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li class="toclevel-1"&gt;3 &lt;span class="toctext"&gt;Estructura del XML&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;br /&gt;Para obtener el texto sin los tags podría acceder a la página&lt;br /&gt;ya procesada por el navegador web, copiar el texto con Ctrl-c y pegarlo con&lt;br /&gt;Ctrl-v en mi editor favorito (las teclas pueden cambiar según el entorno&lt;br /&gt;en el que estemos trabajando). Pero aquí, como mi intención es&lt;br /&gt;mostrar el sed, lo haré con esta herramienta.&lt;br /&gt;&lt;br /&gt;Lo que se me ocurre es sustituir el patrón "&amp;lt;.*&amp;gt;"&lt;br /&gt;por una cadena vacía. Sin embargo el resultado obtendido luego de&lt;br /&gt;ejecutar "sed 's/&amp;lt;.*&amp;gt;//g' temp" es varias líneas&lt;br /&gt;vacías.&lt;br /&gt;&lt;br /&gt;Lo que pasa es que el patrón es ambiguo. Por ejemplo para&lt;br /&gt;"&lt;br /&gt;&lt;h2&gt;Contenido&lt;/h2&gt;" sed comenzaría leyendo desde&lt;br /&gt;el primer "&amp;lt;", pero podría detenerse en el "&amp;gt;"&lt;br /&gt;detrás del primer h2 o en el "&amp;gt;" detrás del segundo&lt;br /&gt;h2. Y los creadores de la herramienta han decidido que se tome siempre la&lt;br /&gt;coincidencia más larga, "the longest match".&lt;br /&gt;Una solución al problema sería, por ejemplo, utilizar el&lt;br /&gt;patrón "&amp;lt;[^&amp;lt;]*&amp;gt;". "[^&amp;lt;]" significa&lt;br /&gt;cualquier caracter que no sea "&amp;lt;". En ese caso el resultado&lt;br /&gt;sería:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Contenido&lt;br /&gt;1 Historia&lt;br /&gt;2 Ventajas del XML&lt;br /&gt;3 Estructura del XML&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;7. Apéndice B: El Editor "ed"&lt;/h2&gt;&lt;br /&gt;Los comandos del sed provienen del editor más primitivo de Unix, llamado&lt;br /&gt;"ed". Este editor, a diferencia de sed que es un editor de flujo, es&lt;br /&gt;un editor común y corriente... bueno, casi. A diferencia de los editores&lt;br /&gt;modernos no es "WYSIWYG" (What You See Is What You Get, o "lo que&lt;br /&gt;vés es lo que obtenés"), o sea que no nos muestra el texto&lt;br /&gt;que estamos editando, simplemente nos permite escribir comandos (más o&lt;br /&gt;menos los mismos que el sed) de manera interactiva.&lt;br /&gt;&lt;br /&gt;El uso de este editor no es común en estos tiempos, ya que la&lt;br /&gt;mayoría de los programadores y administradores de Unix prefieren trabajar&lt;br /&gt;con el "vi". Sin embargo, el ed puede aprovecharse como otro comando&lt;br /&gt;para nuestros scripts cuando necesitamos abrir un archivo, hacer una&lt;br /&gt;edición y volver a grabarlo. En ese caso no precisamos un editor de&lt;br /&gt;flujo como el sed, sino más bien alguno que edite el archivo en el lugar.&lt;br /&gt;&lt;br /&gt;Volvamos al ejemplo de eliminar los espacios sobrantes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Aquí   me pongo a   cantar&lt;br /&gt;al  compás de    la vigüela,&lt;br /&gt;que al hombre  que lo desvela&lt;br /&gt;una   pena     estrordinaria,&lt;br /&gt;como la ave solitaria&lt;br /&gt;con    el cantar se   consuela.&lt;/pre&gt;&lt;br /&gt;Imagínese que el texto se encuentra en el archivo "prueba.txt".&lt;br /&gt;Si lo resolviésemos con el sed, como hicimos en el ejemplo pasado,&lt;br /&gt;obtendríamos el resultado en la salida estándar o en otro archivo. Sin&lt;br /&gt;embargo queremos que los datos permanezcan en "prueba.txt" luego de la&lt;br /&gt;transformación. Por lo que tenemos dos opciones: a) obtener los datos&lt;br /&gt;en un archivo auxiliar y luego reemplazar "prueba.txt" por este&lt;br /&gt;archivo; o b) editar el archivo en el lugar utilizando el "ed".&lt;br /&gt;&lt;br /&gt;El comando para editar el archivo en "ed" es el mismo que en el&lt;br /&gt;"sed" pero con tres salvedades. La primera es que "ed" no&lt;br /&gt;tiene como rango implícito todas las líneas del archivo, por lo&lt;br /&gt;que sí o sí tenemos que indicarle el rango&lt;br /&gt;"1,$" delante del comando. La segunda es que luego de la&lt;br /&gt;transformación debemos ejecutar el comando "w" para grabar&lt;br /&gt;el archivo, ya que "ed" no lo hará automáticamente.&lt;br /&gt;Y la tercera es que los comandos se separan con una nueva línea, y no&lt;br /&gt;con un ";".&lt;br /&gt;&lt;br /&gt;"ed" recibe el nombre del archivo como parámetro y lee los&lt;br /&gt;comandos desde la entrada estándar. También requiere la&lt;br /&gt;opción "-n" para suprimir molestos mensajes. Por lo que&lt;br /&gt;quedaría de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ed -s prueba.txt &amp;lt;&amp;lt;&amp;lt; $'1,$s/ \+/ /g\nw'&lt;/pre&gt;&lt;br /&gt;Pero algunas implementaciones modernas del "sed", como por ejemplo la&lt;br /&gt;de GNU, también poseen la opción "-i" que permite&lt;br /&gt;modificar el archivo en el lugar y obtener el mismo resultado:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sed -i 's/ \+/ /g' prueba.txt&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;8. Final&lt;/h2&gt;&lt;br /&gt;"sed" se encuentra siempre entre mi reducido y selecto repertorio de&lt;br /&gt;herramientas de trabajo. Podría decir que está entre las muy&lt;br /&gt;primeras opciones a la hora de realizar cualquier tipo de transformación&lt;br /&gt;sobre textos extensos y que no conozco otra cosa que lo haga mejor.&lt;br /&gt;&lt;br /&gt;Además de eso he tenido la oportunidad de operar en varios sistemas&lt;br /&gt;tipo Unix distintos y todos poseen la herramienta. Y cuando me encontré&lt;br /&gt;trabajando con sistemas de otro tipo, a falta de alguna mejor opción, he&lt;br /&gt;tenido la necesidad de instalarla. Dicho sea de paso, he conseguido&lt;br /&gt;implementaciones libres en la internet que se instalan fácilmente y sin&lt;br /&gt;ningún tipo de problema.&lt;br /&gt;&lt;br /&gt;La herramienta es más bien compacta, sencilla y poderosa. Por lo que se&lt;br /&gt;logra dominar luego de usarla un par de veces, siempre y cuando se esté&lt;br /&gt;familiarizado con las expresiones regulares. Y si no lo está es muy&lt;br /&gt;recomendable que lea algún tutorial pequeño sobre el asunto y lo&lt;br /&gt;ponga en práctica.&lt;br /&gt;&lt;br /&gt;Hasta aquí espero que haya obtenido una idea acerca del "sed" y&lt;br /&gt;del provecho que le puede sacar tanto para crear scripts o para transformar&lt;br /&gt;todo tipo de textos.&lt;br /&gt;&lt;br /&gt;Para más información sugiero que lea la documentación de&lt;br /&gt;la implementación en su sistema operativo. Si tiene GNU instalado&lt;br /&gt;escriba "info sed". También encontrará muchos textos&lt;br /&gt;escritos en todos los idiomas en la internet, lo que es un punto a favor&lt;br /&gt;del uso del "sed".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-5134365655508697160?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/5134365655508697160/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=5134365655508697160' title='3 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5134365655508697160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/5134365655508697160'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2009/03/presentacion-del-sed-copyright-c-2009.html' title='Presentación del sed'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-4871570340629602993</id><published>2008-11-25T23:22:00.011-02:00</published><updated>2009-08-30T05:20:57.622-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tcl/Tk'/><category scheme='http://www.blogger.com/atom/ns#' term='Scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='Programa'/><title type='text'>TkPong</title><content type='html'>&lt;p&gt;Screenshoot&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://1.bp.blogspot.com/_FDA3N96YFtA/SSylsKA2p4I/AAAAAAAAAAw/I62t0ZWgncg/s400/tkpong-screenshoot.png" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;TkPong is a pong implemented by H&amp;eacute;ctor Francisco Hern&amp;aacute;ndez in Tcl/Tk. This is Free/Libre Software. You will find the code &lt;a href="http://wiki.tcl.tk/23959"&gt;here&lt;/a&gt; in the Tcl/Tk wiki.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;TkPong es un pong implementado por H&amp;eacute;ctor Francisco Hern&amp;aacute;ndez en Tcl/Tk. Es software libre, Encontrará el código &lt;a href="http://wiki.tcl.tk/23959"&gt;aquí&lt;/a&gt; en la wiki de Tcl/Tk.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-4871570340629602993?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/4871570340629602993/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=4871570340629602993' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4871570340629602993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/4871570340629602993'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2008/11/tkpong.html' title='TkPong'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_FDA3N96YFtA/SSylsKA2p4I/AAAAAAAAAAw/I62t0ZWgncg/s72-c/tkpong-screenshoot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-1444992386115019550</id><published>2008-07-13T00:00:00.006-03:00</published><updated>2009-08-30T05:18:59.521-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Programa'/><title type='text'>jsGorilla</title><content type='html'>&lt;p&gt;&lt;br /&gt;Héctor Francisco Hernández &amp;lt;hectorfh@gmail.com&amp;gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_FDA3N96YFtA/SnZHf8wS9ZI/AAAAAAAAACQ/xLabdt6_L8U/s1600-h/jsgorilla.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_FDA3N96YFtA/SnZHf8wS9ZI/AAAAAAAAACQ/xLabdt6_L8U/s400/jsgorilla.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5365554620268737938" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;a href="http://hectorscripting.googlecode.com/files/jsgorilla-0.4.2.zip"&gt;Download&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-1444992386115019550?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/1444992386115019550/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=1444992386115019550' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1444992386115019550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/1444992386115019550'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2008/07/jsgorilla.html' title='jsGorilla'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_FDA3N96YFtA/SnZHf8wS9ZI/AAAAAAAAACQ/xLabdt6_L8U/s72-c/jsgorilla.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-3589915617986962032</id><published>2008-01-10T11:41:00.005-02:00</published><updated>2009-08-30T05:17:41.873-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>RMI: Remote Method Invocation (Invocación de Método Remota)</title><content type='html'>&lt;p&gt;&lt;br /&gt;Copyright (c) 2008 Héctor Francisco Hernández &amp;lt;hectorfh@gmail.com&amp;gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Se otorga permiso para copiar, distribuir y/o modificar este documento bajo los términos de la Licencia de Documentación Libre de GNU, Versión 1.3 o cualquier otra versión posterior publicada por la Free Software Foundation; sin Secciones Invariantes ni Textos de Cubierta Delantera ni Textos de Cubierta Trasera. Una copia de la licencia se encuentra en http://www.gnu.org/copyleft/fdl.html.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Introducción.&lt;br&gt;&lt;/h3&gt;&lt;br&gt;RMI es un protocolo propietario de Java que permite que métodos de objetos que existen en una máquina virtual puedan ser invocados desde otros objetos en otra máquina virtual, probablemente en un host distinto.&lt;br&gt;&lt;br&gt;RMI sólo permite la comunicación entre tecnología Java. Si se requiere comunicar con otras tecnologías debe usarse CORBA o SOAP.&lt;br&gt;&lt;br&gt;Al estar específicamente diseñado para Java, RMI puede darse el lujo de ser muy amigable para los programadores, proveyendo pasaje por referencia de objetos (cosa que no hace SOAP), "recolección de basura" distribuida y pasaje de tipos arbitrarios (funcionalidad no provista por CORBA).&lt;br&gt;&lt;br&gt;Por medio de RMI un programa puede hacer disponible un objeto en la red. Otro programa entonces podría invocar métodos de dicho objeto como si invocara métodos de objetos propios, de un modo transparente al programador, sin tener que lidiar con sockets de bajo nivel.&lt;br&gt;&lt;br&gt;Cuando un programador invoca un método de un objeto remoto, los parámetros son serializados (convertidos en un flujo de bytes capaz de ser enviados a través de un socket). Luego se envían a través de la red, mientras que el método que hizo la invocación queda esperando. El método remoto realiza el procesamiento, serializa el valor de retorno y se lo devuelve al llamador. Esto implica que el pasaje de parámetros que no tienen interfaz remota definida (objetos no remotos), cuando se trata de métodos remotos, es por copia.&lt;br&gt;&lt;br&gt;Por este motivo se requiere que los parámetros del método remoto y del dato que retorna sean de clases que se puedan serializar (en Java, que implementen la interfaz "Serializable").&lt;br&gt;&lt;br&gt;El encargado de hacer públicos los objetos remotos es el registro RMI. Se trata de un servicio, cuyo puerto TCP por defecto es el 1099 (aunque es posible elegir otro), que mantiene información acerca de los objetos exportados y sus correspondientes direcciones. El servidor debe registrar en él sus objetos remotos mediante el método "Naming.bind("dirección", objeto)" y el cliente debe solicitarlos llamando a "Naming.lookup("dirección")".&lt;br&gt;&lt;br&gt;&lt;div id="rpyb" style="padding: 1em 0pt; text-align: center;"&gt;&lt;img style="width: 355px; height: 181px;" src="http://docs.google.com/File?id=dc94ptfk_31ftn4p7c6"&gt;&lt;/div&gt;&lt;br&gt;&lt;h3&gt;Haciendo uso de RMI.&lt;br&gt;&lt;/h3&gt;Para aprender más hacemos uso de la tecnología por nuestra cuenta.&lt;br&gt;&lt;br&gt;Para utilizar objetos remotos, lo primero que debemos hacer es definir una interfaz con los métodos que serán utilizados remotamente. Está especificado que está interfaz debe heredar de la interfaz "Remote".&lt;br&gt;&lt;br&gt;Los métodos remotos lanzan excepciones de la clase "RemoteException", y no de la clase "Exception".&lt;br /&gt;&lt;pre style="background: silver none repeat scroll 0% 50%"&gt;&lt;br /&gt;import java.rmi.Remote;&lt;br /&gt;import java.rmi.RemoteException;&lt;br /&gt;&lt;br /&gt;public interface InterfazRemota extends Remote&lt;br /&gt;{&lt;br /&gt;  public String recibirMensaje(String mensaje) throws RemoteException;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Aunque el cliente no conozca la implementación del objeto remoto, deberá conocer su interfaz para invocar los métodos, por lo tanto deberemos compilar el cliente también utilizando esa interfaz.&lt;/p&gt;&lt;br&gt;Luego implementamos la clase del objeto remoto. Las clases remotas deben heredar de "UnicastRemoteObject".&lt;br&gt;&lt;br /&gt;&lt;pre style="background: silver none repeat scroll 0% 50%"&gt;&lt;br /&gt;import java.rmi.server.UnicastRemoteObject;&lt;br /&gt;import java.rmi.RemoteException;&lt;br /&gt;import java.net.InetAddress;&lt;br /&gt;&lt;br /&gt;public class ClaseRemota extends UnicastRemoteObject&lt;br /&gt;    implements InterfazRemota&lt;br /&gt;{&lt;br /&gt;  public ClaseRemota() throws RemoteException&lt;br /&gt;  {&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public String recibirMensaje(String mensaje)&lt;br /&gt;      throws RemoteException&lt;br /&gt;  {&lt;br /&gt;    try {&lt;br /&gt;      System.out.println(mensaje);&lt;br /&gt;      return "Soy " +&lt;br /&gt;          InetAddress.getLocalHost().getHostAddress() +&lt;br /&gt;          " y el mensaje ha sido impreso en mi consola.";&lt;br /&gt;    }&lt;br /&gt;    catch (Exception e)&lt;br /&gt;    {&lt;br /&gt;      throw new RemoteException("Fallo en el servidor");&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Ahora ya podemos terminar el servidor. Deberá instanciar el objeto y hacerlo disponible en la red a través del registro "RMI". Para eso existe la función "Naming.bind(dirección, objeto)" que asocia nuestro objeto remoto con un nombre virtual del formato "//host:port/name". Utilizaremos ese nombre para buscar el objeto remoto desde el proceso cliente más tarde.&lt;br&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre style="background: silver none repeat scroll 0% 50%"&gt;&lt;br /&gt;import java.rmi.Naming;&lt;br /&gt;import java.net.InetAddress;&lt;br /&gt;&lt;br /&gt;public class Servidor&lt;br /&gt;{&lt;br /&gt;  public static void main(String[] args)&lt;br /&gt;  {&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;      InterfazRemota objetoRemoto = new ClaseRemota();&lt;br /&gt;      Naming.bind("//" +&lt;br /&gt;          InetAddress.getLocalHost().getHostAddress() +&lt;br /&gt;          ":1234/PruebaRMI", objetoRemoto);&lt;br /&gt;    }&lt;br /&gt;    catch (Exception e)&lt;br /&gt;    {&lt;br /&gt;      e.printStackTrace();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Hemos escogido el puerto "1234", sin embargo, de omitir el puerto TCP, RMI utiliza por defecto 1099.&lt;br&gt; &lt;/p&gt;&lt;br&gt; El servidor ya está en condiciones de ser compilado y ejecutado. Para ello alcanzará con el comando "javac *java". Luego para correrlo debemos previamente ejecutar el registro RMI para el correspondiente puerto (comando "rmiregistry 1234" en nuestro glorioso Slackware GNU/Linux) y luego el programa servidor propiamente dicho (comando "java Servidor").&lt;br&gt;&lt;br&gt;Ahora haremos un programita cliente que simplemente busque nuestro objeto remoto en la red y ejecute el método "recibirMensaje" con el parámetro "Hola Mundo!". Para ahorrar tiempo vamos a suponer que la dirección IP del servidor es "10.0.0.10", siendo esta la dirección de la máquina en la que se hizo el experimento.&lt;br&gt;&lt;br&gt;Para encontrar "objetoRemoto" se utiliza la función "Naming.lookup(dirección)".&lt;br&gt;&lt;br /&gt;&lt;pre style="background: silver none repeat scroll 0% 50%"&gt;&lt;br /&gt;import java.rmi.Naming;&lt;br /&gt;&lt;br /&gt;public class Cliente&lt;br /&gt;{&lt;br /&gt;  public static void main(String[] args)&lt;br /&gt;  {&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;      InterfazRemota objetoRemoto = (InterfazRemota)&lt;br /&gt;          Naming.lookup("rmi://10.0.0.10:1234/PruebaRMI");&lt;br /&gt;      String retval = objetoRemoto.recibirMensaje("Hola Mundo!");&lt;br /&gt;      System.out.println("Mensaje del servidor: " + retval);&lt;br /&gt;    }&lt;br /&gt;    catch (Exception e)&lt;br /&gt;    {&lt;br /&gt;      e.printStackTrace();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Compilamos el cliente con el comando "javac Cliente.java" asegurándonos que "InterfazRemota" está en el "classpath" y lo ejecutamos. Como resultado veremos en la consola del servidor el mensaje "Hola Mundo!" que ha llegado en la invocación al método remoto, y en la del cliente "Mensaje del servidor: Soy 10.0.0.10 y el mensaje ha sido impreso en mi consola.".&lt;br&gt;&lt;br&gt;&lt;h3&gt;Conclusión.&lt;/h3&gt;Según la experiencia que hemos tenido con RMI, todo se ve transparente y amigable al programador. Debido a que está pensado exclusivamente para Java, la integración con esta tecnología es perfecta y sin dolores de cabeza. Sin embargo nos vemos bastante limitados, para no decir del todo, en cuanto a interoperabilidad con el resto del universo no Java.&lt;br&gt;&lt;br&gt;&lt;h3&gt;Referencias.&lt;/h3&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;Sitio Oficial de Java (http://java.sun.com/)&lt;/li&gt;&lt;li&gt;Wikipedia (http://es.wikipedia.org/)&lt;/li&gt;&lt;li&gt;Sitio de O'Reilly (http://www.oreillynet.com/)&lt;br&gt;&lt;/li&gt;&lt;li&gt;Proactiva Calidad (http://www.proactiva-calidad.com/)&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-3589915617986962032?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/3589915617986962032/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=3589915617986962032' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/3589915617986962032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/3589915617986962032'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2008/01/rmi-remote-method-invocation-invocacin.html' title='RMI: Remote Method Invocation (Invocación de Método Remota)'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-115177193724522870</id><published>2006-07-01T12:30:00.001-03:00</published><updated>2009-08-30T05:17:01.442-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lenguaje C'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><title type='text'>Programación GUI con Motif.</title><content type='html'>&lt;h2&gt;1. &amp;iquest;Qu&amp;eacute; es Motif?&lt;/h2&gt;&lt;p&gt;Motif es, ante todo, un est&amp;aacute;ndar (IEEE 1295) creado en los 80', el cual define una API en lenguaje C para el desarrollo de interfaces gr&amp;aacute;ficas (GUIs) sobre X Window (para entornos Unix). Tambi&amp;eacute;n especifica una &amp;quot;Gu&amp;iacute;a de estilo&amp;quot;, detallando el aspecto que deber&amp;iacute;a tener una aplicaci&amp;oacute;n Motif.&lt;br /&gt;Por supuesto, esta denominaci&amp;oacute;n  tambi&amp;eacute;n se aplica a la biblioteca que implementa el est&amp;aacute;ndar, y fue originalmente desarrollada por el Open Source Fundation, para competir con OpenLook. Actualmente es mantenida por el Open Group. Existen varias implementaciones de Motif adem&amp;aacute;s de la original, entre ellas OpenMotif (una versi&amp;oacute;n libre para sistemas operativos de c&amp;oacute;digo abierto, como GNU/Linux o FreeBSD), Lesstif y SGI Motif.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2. &amp;iquest;Porque Motif?&lt;/h2&gt;&lt;p&gt;Habiendo tantas bibliotecas (&amp;quot;toolkits&amp;quot;) disponibles (entre ellas GTK+, creada precisamente para reemplazar a Motif en el desarrollo de El Gimp), cabe preguntarse que utilidad tiene aprender a programar con esta biblioteca. Bien, en primer lugar, porque se encuentra estandarizada. Esto significa que existe estabilidad en la API, y si surgen nuevas adiciones a la biblioteca, probablemente no ser&amp;aacute; necesario modificar el c&amp;oacute;digo fuente de nuestro programa. A pesar de sus a&amp;ntilde;os, sigue siendo la biblioteca de ventanas nativa de los sistemas Unix. Se ha utilizado en miles de programas, y hoy d&amp;iacute;a se mantiene como el toolkit l&amp;iacute;der en estaciones de trabajo profesionales, para el desarrollo de aplicaciones cr&amp;iacute;ticas. Tambi&amp;eacute;n es relativamente peque&amp;ntilde;a, y muy eficiente (es probablemente la biblioteca de este tipo m&amp;aacute;s r&amp;aacute;pida, en parte por su sencillez). Ese car&amp;aacute;cter minimalista hace que Motif no sea tan &amp;quot;bonita&amp;quot; en comparaci&amp;oacute;n con GTK+ o Qt, pero es sin duda eficaz. Incluso es posible compilarla est&amp;aacute;ticamente para obtener ejecutables de tama&amp;ntilde;o razonable, y prescindir de la instalaci&amp;oacute;n de bibliotecas din&amp;aacute;micas en el sistema destino. Motif tambi&amp;eacute;n soporta Unicode, por lo que es apta para aplicaciones internacionalizadas.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;3. Obteniendo la biblioteca.&lt;/h2&gt;&lt;p&gt;La &amp;uacute;ltima especificaci&amp;oacute;n de Motif es la 2.1. Existen muchas implementaciones de este est&amp;aacute;ndar, pero la mayor&amp;iacute;a de ellas son comerciales (debemos pagar por las licencias). La principal, por supuesto, es la del Open Group. Sin embargo, las versiones que se tendr&amp;aacute;n en cuenta en este art&amp;iacute;culo son las disponibles gratuitamente: OpenMotif y Lesstif. &lt;/p&gt;&lt;p&gt;OpenMotif  es una versi&amp;oacute;n libre, siempre que las aplicaciones se utilicen en sistemas operativos que tambi&amp;eacute;n sean libres. La &amp;uacute;ltima versi&amp;oacute;n estable es la 2.2, pero puede obtenerse la beta de la 2.3.&lt;/p&gt;&lt;p&gt;Lesstif es un proyecto de un grupo de programadores denominado &amp;quot;The Hungry Programmers&amp;quot;. Si bien a&amp;uacute;n no implementa la totalidad del est&amp;aacute;ndar, es una versi&amp;oacute;n muy completa y evolucionada. Tiene licencia LGPL, por lo que resulta menos restrictiva que OpenMotif, y se puede usar en cualquier entorno Unix (o incluso bajo Windows, mediante Cygwin). La &amp;uacute;ltima versi&amp;oacute;n es la 0.95.0.&lt;/p&gt;&lt;p&gt; Los que posean distribuciones de GNU/Linux basadas en Debian, pueden buscar en los repositorios de dichos sistemas &amp;aacute;mbas bibliotecas.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;4. Widgets, Gadgets y generalidades.&lt;/h2&gt;&lt;p&gt;Motif es un toolkit construido sobre la biblioteca Xt Intrinsics (X Toolkit), que a su vez es soportada por Xlib (la API b&amp;aacute;sica de X Window). Xt ofrece una serie de estructuras y funciones que pueden usarse como base para construir conjuntos de &amp;quot;widgets&amp;quot;. Tambi&amp;eacute;n esconde la mayor parte de la complejidad de Xlib, facilitando la programaci&amp;oacute;n. Tanto Motif como Xt est&amp;aacute;n dirigidas por eventos, lo que en pocas palabras significa que la aplicaci&amp;oacute;n entra, luego de su ejecuci&amp;oacute;n, en un bucle o &amp;quot;loop&amp;quot;, manejando mensajes de X Window hasta que se ordena cerrar la aplicaci&amp;oacute;n (se sale del bucle). Este tutorial no discutir&amp;aacute; las caracter&amp;iacute;sticas distribuidas de X Window, y tampoco analizar&amp;aacute; en profundidad la biblioteca Xt.&lt;/p&gt;&lt;p&gt;Los &amp;quot;widgets&amp;quot; son los elementos que constituyen una interfaz gr&amp;aacute;fica (GUI), como por ejemplo ventanas, botones, etiquetas, etc. Los mismos operan de forma independiente de la aplicaci&amp;oacute;n, salvo por acciones predefinidas por el usuario. En Motif, los widgets se encuentran declarados en archivos de cabecera, como &amp;lt;MainW.h&amp;gt;, &amp;lt;PushB.h&amp;gt;, &amp;lt;Text.h&amp;gt;, entre muchos otros. Pueden encontrarse en la carpeta &amp;lt;Xm&amp;gt;, habitualmente ubicada en &amp;lt;/usr/include&amp;gt;. Puede observarse que en dicha carpeta hay otros archivos con los mismos nombres que los citados anteriormente, con la salvedad de que terminan con una letra 'P' (por ejemplo, &amp;lt;PushBP.h&amp;gt;). Estos archivos son cabeceras privadas, y representan funciones y tipos de datos que se ocultan de la interfaz p&amp;uacute;blica de Motif. Esto es as&amp;iacute; porque la biblioteca (al igual que Xt) est&amp;aacute; orientada a objetos, y por ende implementa conceptos como encapsulamiento y herencia (mediante la definici&amp;oacute;n de clases de widgets), todo esto a pesar de estar escrita en C, un lenguaje que no brinda soporte expl&amp;iacute;cito para dicho paradigma. Bizarro, sin lugar a dudas. Por cierto, tambi&amp;eacute;n se pueden encontrar archivos cuyos nombres terminan con G. Estos son &amp;quot;gadgets&amp;quot;, y son similares a los widgets en su aspecto. Sin embargo, el comportamiento de estos gadgets no est&amp;aacute; definido dentro de los mismos, sino que es responsabilidad del widget que los contiene. Por ejemplo, un gadget no se redibuja a si mismo en forma autom&amp;aacute;tica. Poseen la ventaja de ser m&amp;aacute;s &amp;quot;ligeros&amp;quot; que los widgets (en lo que respecta a consumo de recursos), pero en las &amp;uacute;ltimas versiones de Motif los widgets est&amp;aacute;n m&amp;aacute;s optimizados (al igual que lo est&amp;aacute; X Windows), por lo que no es com&amp;uacute;n usar gadgets, y en el presente art&amp;iacute;culo no se los volver&amp;aacute; a mencionar.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;5. Funciones de la biblioteca.&lt;/h2&gt;&lt;p&gt;Todo programa Motif necesita de dos elementos b&amp;aacute;sicos: un &amp;quot;Application Context&amp;quot; (una estructura que utiliza Xt para manejar informaci&amp;oacute;n interna relacionada con nuestra aplicaci&amp;oacute;n), y un &amp;quot;Top Level Widget&amp;quot;, o widget principal (el cu&amp;aacute;l representa el control de m&amp;aacute;s alta jerarqu&amp;iacute;a, y ser&amp;aacute; el &amp;quot;padre&amp;quot; de todos los dem&amp;aacute;s widgets).  Adem&amp;aacute;s, los widgets disponen de recursos (&amp;quot;resources&amp;quot;), los cuales son atributos configurables. Hay un gran n&amp;uacute;mero de recursos por cada widget, en parte debido a que son heredables. Los recursos tienen un nombre, que generalmente comienzan con &amp;quot;XmN&amp;quot;; por ejemplo, los botones (PushButtons) tienen recursos como XmNlabelString (el texto del bot&amp;oacute;n) o XmNshadowThickness (el grosor de la sombra del bot&amp;oacute;n). Un tipo de recurso especial es el denominado &amp;quot;callback resource&amp;quot;. El mismo es un puntero a una funci&amp;oacute;n que debe ejecutarse cuando se efect&amp;uacute;a cierta acci&amp;oacute;n sobre el widget. Volviendo al caso del PushButton, el recurso XmNactivateCallback apunta a una funci&amp;oacute;n que ser&amp;aacute; llamada al pulsar el bot&amp;oacute;n (click con el bot&amp;oacute;n izquierdo).  Los recursos se pueden introducir al momento de crear el widget, o bien pueden ser modificados posteriormente con las siguientes funciones:&lt;/p&gt;&lt;code&gt;void XtSetValues(Widget hW, ArgList pArgs, Cardinal iNumArgs);&lt;br /&gt;void XtVaSetValues(Widget hW, ...);&lt;/code&gt;&lt;p&gt;En la primera, hW es el widget, pArgs es un array de elementos &amp;quot;Arg&amp;quot; (los cuales contienen cadenas de caracteres que representan a los recursos), y iNumArgs es simplemente un entero que indica el n&amp;uacute;mero de elementos del array pArgs. En el caso de XtVaSetValues, adem&amp;aacute;s del widget, se pasan los par&amp;aacute;metros de a pares (el nombre del recurso primero, y luego el valor del mismo), terminando con un car&amp;aacute;cter nulo (&amp;quot;NULL&amp;quot;). Por ejemplo, para cambiar el texto y el grosor de la sombra de un bot&amp;oacute;n previamente creado, se pueden usar las llamadas:&lt;/p&gt;&lt;br /&gt;&lt;code&gt;XmString sText = XmStringCreateLocalized (&amp;quot;Aceptar&amp;quot;);&lt;br /&gt;XtVaSetValues(hW, XmNlabelString, sText, XmNshadowThickness, 5, NULL );&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;XmString es un tipo definido por Motif para manejar strings con soporte internacionalizado.  Para crear los widgets, suelen llamarse a funciones del siguiente estilo:&lt;p&gt;&lt;br /&gt;&lt;code&gt;Widget XmCreate&amp;lt;nombre del widget&amp;gt;(Widget hWparent, String szName,     ArgList pArgs, Cardinal iNumArgs);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;hWparent es el widget padre (normalmente, el que contiene al widget que estamos creando), szName es el nombre del widget, pArgs es el array de recursos, y por &amp;uacute;ltimo iNumArgs es la cantidad de elementos de pArgs.  Cada vez que se crea un widget, debe llamarse a la siguiente funci&amp;oacute;n: &lt;/p&gt;&lt;br /&gt;&lt;code&gt;void XtManageChild(Widget hWchild);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;donde hWchild es el widget que se acaba de crear. Esta llamada har&amp;aacute; que Xt se encargue de administrar al widget. Existen otras funciones que habr&amp;aacute; que utilizar, como XtVaOpenApplication, XtAddCallBack,  XtRealizeWidget y XtAppMainLoop. Las mismas se explicar&amp;aacute;n brevemente con un ejemplo. Probablemente ya haya notado los prefijos &amp;quot;Xm&amp;quot; y &amp;quot;Xt&amp;quot; en todas las funciones expuestas hasta ahora. No es dif&amp;iacute;cil adivinar su utilidad: &amp;quot;Xm&amp;quot; se refiere a las funciones que corresponden a la API de Motif, y &amp;quot;Xt&amp;quot; hace lo propio con X Toolkit. Se trata de una convenci&amp;oacute;n muy popular para evadir las colisiones de espacio de nombres.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;6. Un ejemplo sencillo&lt;/h2&gt;&lt;p&gt;El siguiente c&amp;oacute;digo representa uno de los programas Motif mas elementales, y est&amp;aacute; basado en un ejemplo del Manual del Programador Motif:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/* &amp;lt;hello.c&amp;gt; Ejemplo de programaci&amp;oacute;n Motif */&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*01*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; #include &amp;lt;Xm/PushB.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*02*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; button_pushed_cb (Widget hWidget, XtPointer pClientData, XtPointer pCallData)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*03*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*04*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   printf (&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;&amp;quot;&amp;iexcl;Hola Mundo!&amp;quot;&lt;/span&gt;&lt;span style="color: #ff00ff;"&gt;\n&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*05*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*06*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*07*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; main (&lt;/span&gt;&lt;span style="color: #800000;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; argc, &lt;/span&gt;&lt;span style="color: #800000;"&gt;char&lt;/span&gt;&lt;span style="color: #000000;"&gt; *argv[])&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*08*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*09*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   Widget hToplevel, hButton;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*10*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   XtAppContext  hApp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*11*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   Arg sArgs[&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;];&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*12*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*13*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   XtSetLanguageProc (NULL, NULL, NULL);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*14*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   hToplevel = XtVaOpenApplication (&amp;amp;hApp, &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"Hello"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, NULL, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &amp;amp;argc, argv,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*15*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;                                    NULL,sessionShellWidgetClass, NULL);    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*16*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*17*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   hButton = XmCreatePushButton (hToplevel, &lt;/span&gt;&lt;span style="color: #dd0000;"&gt;"button"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, NULL, NULL);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*18*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*19*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   XmString sText = XmStringCreateLocalized (&lt;/span&gt;&lt;span style="color: #dd0000;"&gt;&amp;quot;Presione, por favor &amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*20*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   XtVaSetValues(hButton, XmNlabelString, sText, NULL);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*21*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   XtAddCallback (hButton, XmNactivateCallback, button_pushed_cb, NULL);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*22*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*23*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   XtManageChild (hButton);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*24*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   XtRealizeWidget (hToplevel);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*25*/&lt;/span&gt;&lt;span style="color: #000000;"&gt;   XtAppMainLoop (hApp);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;color: #808080;"&gt;/*26*/&lt;/span&gt;&lt;span style="color: #000000;"&gt; }&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;Puede compilarse &amp;lt;hello.c&amp;gt; con el siguiente comando:&lt;/p&gt;&lt;code&gt; cc -o hello hello.c -lXm -lXt -lX11&lt;/code&gt;&lt;p&gt;Observe el orden en el que se enlazan las bibliotecas (no debe alterarlo). El resultado de ejecutar el ejemplo es una peque&amp;ntilde;a ventana, cuyo &amp;uacute;nico contenido es un bot&amp;oacute;n, el cu&amp;aacute;l al pulsarlo imprimir&amp;aacute; un saludo en la salida del terminal. &lt;br /&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/2095/3176/1600/hello.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger/2095/3176/320/hello.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;En la primer l&amp;iacute;nea se incluye el archivo de cabecera que corresponde al widget PushButton. Luego se define una funci&amp;oacute;n, button_pushed_cb, que se llamar&amp;aacute; al presionar el bot&amp;oacute;n. Observe los &amp;uacute;ltimos tres caracteres del nombre de la funci&amp;oacute;n; es una convenci&amp;oacute;n que se recomienda usar para las funciones &amp;quot;callbacks&amp;quot; (de retrollamada). Esta funci&amp;oacute;n ser&amp;aacute; el &amp;uacute;nico &amp;quot;callback resource&amp;quot; que se utilizar&amp;aacute; en este programa.  Ya dentro del main, en la l&amp;iacute;nea 12 se declaran dos widgets (uno para el programa en s&amp;iacute;, y otro para el PushButton). En la l&amp;iacute;nea 13 se declara el &amp;quot;Application Context&amp;quot; de &amp;lt;hello.c&amp;gt;.&lt;/p&gt;&lt;p&gt;La funci&amp;oacute;n XtSetLanguageProc invocada en la l&amp;iacute;nea 15 configura una funci&amp;oacute;n para el manejo del lenguaje local, asociada al &amp;quot;application context&amp;quot; del programa. En este caso, todos sus par&amp;aacute;metros son NULL, por lo que se usa el procedimiento por defecto (es lo m&amp;aacute;s com&amp;uacute;n).&lt;/p&gt;&lt;p&gt;En la l&amp;iacute;nea 16 se llama a XtVaOpenApplication. La misma realiza una variedad de acciones, de las cuales las m&amp;aacute;s importantes son el crear el &amp;quot;application context&amp;quot; de nuestro programa, y llamar a XtOpenDisplay para abrir una ventana de X Window, sobre la cu&amp;aacute;l se mostrar&amp;aacute; la aplicaci&amp;oacute;n. Los par&amp;aacute;metros usados en el ejemplo son los m&amp;aacute;s comunes, como por ejemplo el tercero (el nombre de la aplicaci&amp;oacute;n), o el octavo (la &amp;quot;clase&amp;quot; del widget TopLevel). Tambi&amp;eacute;n se observa que se le pasan los par&amp;aacute;metros obtenidos de la l&amp;iacute;nea de comandos (argc y argv). De hecho, el t&amp;iacute;tulo de la ventana de nuestro ejemplo ser&amp;aacute; &amp;quot;hello&amp;quot;, el cu&amp;aacute;l es por supuesto el valor de argv[0]. No es el objetivo de este tutorial describir a Xt, por lo que se omitir&amp;aacute; el detalle de esta funci&amp;oacute;n. Pueden consultarse los enlaces recomendados para encontrar la documentaci&amp;oacute;n de Xt.&lt;/p&gt;&lt;p&gt;En la l&amp;iacute;nea 19 se crea un PushButton (cuyo widget se guarda en la variable hButton), y en las l&amp;iacute;neas 21 y 22 se le asigna una etiqueta al mismo. En la siguiente l&amp;iacute;nea se llama a XtAddCallback, la cu&amp;aacute;l tiene el siguiente prototipo:&lt;/p&gt;&lt;br /&gt;&lt;code&gt;void XtAddCallback(Widget hW, String szCallbackName, &lt;br /&gt;    XtCallbackProc pfCallback, XtPointer pClientData);&lt;/code&gt;&lt;br /&gt;&lt;p&gt;En la llamada, hW es el widget a configurar; szCallbackName es el nombre del recurso; pfCallback es un puntero a funci&amp;oacute;n, y pClientData es un par&amp;aacute;metro que se le pasar&amp;aacute; a la funci&amp;oacute;n button_pushed_cb cuando sea invocada. En forma gen&amp;eacute;rica, el prototipo de las funciones de retrollamada debe ser:&lt;/p&gt;&lt;code&gt;void myfunc_cb(Widget hW, XtPointer pClientData, XtPointer pCallData);&lt;/code&gt;&lt;p&gt;en donde hW es el widget al que se asoci&amp;oacute; la funci&amp;oacute;n. pClientData es un valor adicional, el cu&amp;aacute;l se registra al llamar a XtAddCallback; y por &amp;uacute;ltimo, pCallData es un par&amp;aacute;metro que el widget le pasa a myfunc_cb cuando la invoca. Este &amp;uacute;ltimo par&amp;aacute;metro depende del tipo de callback registrado, y suele ser un puntero a alguna estructura con informaci&amp;oacute;n acerca del estado del widget.&lt;/p&gt;&lt;p&gt;En la l&amp;iacute;nea 25 se asocia el bot&amp;oacute;n a nuestra aplicaci&amp;oacute;n, y en la l&amp;iacute;nea 26 se llama a XtRealizeWidget. Esta &amp;uacute;ltima funci&amp;oacute;n tiene una tarea un tanto compleja, la cual consiste (en s&amp;iacute;ntesis), en recorrer la jerarqu&amp;iacute;a de widgets (a partir del widget pasado como par&amp;aacute;metro, o sea hTopLevel), inicializarlos y volverlos visibles. Por &amp;uacute;ltimo, en la l&amp;iacute;nea 27 se llama a XtAppMainLoop, que se encargar&amp;aacute; de entrar en un bucle infinito y procesar eventos de X Window, hasta que se ordene cerrar la ventana, en cuyo caso interrumpir&amp;aacute; el bucle y dar&amp;aacute; por terminada la ejecuci&amp;oacute;n.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;7. Enlaces recomendados&lt;/h2&gt;&lt;br /&gt;&lt;a href="http://www.opengroup.org/motif/"&gt;http://www.opengroup.org/motif/&lt;/a&gt;&lt;br /&gt;&lt;p&gt;El sitio oficial de Motif. Aqu&amp;iacute; pueden adquirirse licencias comerciales de la biblioteca.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.motifzone.com"&gt;http://www.motifzone.com&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Documentaci&amp;oacute;n y foros sobre Motif. Adem&amp;aacute;s, pueden bajarse las &amp;uacute;ltimas versiones de OpenMotif.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.lesstif.org "&gt;http://www.lesstif.org &lt;/a&gt;&lt;br /&gt;&lt;p&gt;Sitio oficial de Lesstif, la implementaci&amp;oacute;n LGPL de Motif.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ist.co.uk/motif/books/vol6A/BookTOC.fm.html"&gt;http://www.ist.co.uk/motif/books/vol6A/BookTOC.fm.html&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Manual del programador de Motif. Imprescindible para desarrollar aplicaciones serias.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://docs.linux.cz/programming/gui/motif/motif.html"&gt;http://docs.linux.cz/programming/gui/motif/motif.html&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Muy buen tutorial de Motif (algo desactualizado, pero igual muy recomendable).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lesstif.sourceforge.net/doc/super-ux/g1ae03e/part1/contents.html#Part1"&gt;http://lesstif.sourceforge.net/doc/super-ux/g1ae03e/part1/contents.html#Part1&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Manual de Xt, importante para entender con un poco m&amp;aacute;s de profundidad la programaci&amp;oacute;n en X Windows.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-115177193724522870?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/115177193724522870/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=115177193724522870' title='3 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/115177193724522870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/115177193724522870'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2006/07/programacin-gui-con-motif.html' title='Programaci&amp;oacute;n GUI con Motif.'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-115061135456715766</id><published>2006-06-18T03:15:00.001-03:00</published><updated>2009-08-30T05:15:52.366-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lenguaje C'/><title type='text'>Cómo intercambiar el valor de dos variables sin utilizar una tercera.</title><content type='html'>&lt;P&gt;Cualquier alumno de programaci&amp;oacute;n&lt;br /&gt;b&amp;aacute;sica podr&amp;iacute;a reconocer el siguiente c&amp;oacute;digo:&lt;/P&gt;&lt;br /&gt;&lt;P&gt;&lt;CODE&gt;aux = x;&lt;BR&gt;x = y;&lt;BR&gt;y = aux;&lt;/CODE&gt;&lt;/P&gt;&lt;br /&gt;&lt;P&gt;Se trata del cl&amp;aacute;sico intercambio&lt;br /&gt;de variables.&lt;/P&gt;&lt;br /&gt;&lt;P&gt;Sin embargo existen otras formas de&lt;br /&gt;intercambiar el valor de dos variables; formas que no requieren&lt;br /&gt;utilizar otra auxiliar.&lt;/P&gt;&lt;br /&gt;&lt;P&gt;Aqu&amp;iacute; expondr&amp;eacute; dos que&lt;br /&gt;conozco, la primera utilizando aritm&amp;eacute;tica b&amp;aacute;sica y la&lt;br /&gt;segunda utilizando &amp;aacute;lgebra de Bool.&lt;/P&gt;&lt;br /&gt;&lt;H2&gt;Utilizando aritm&amp;eacute;tica b&amp;aacute;sica.&lt;/H2&gt;&lt;br /&gt;&lt;P&gt;El c&amp;oacute;digo es el siguiente:&lt;/P&gt;&lt;br /&gt;&lt;P&gt;&lt;CODE&gt;x = x + y;&lt;BR&gt;y = x - y;&lt;BR&gt;x = x - y;&lt;/CODE&gt;&lt;/P&gt;&lt;br /&gt;&lt;P&gt;Este c&amp;oacute;digo es muy interesante,&lt;br /&gt;sin embargo es posible que, si la suma de “x” y “y” diera un&lt;br /&gt;valor muy alto, provoquemos un desbordamiento (overflow) en la&lt;br /&gt;variable “x” y todo salga mal.&lt;/P&gt;&lt;br /&gt;&lt;H2&gt;Utilizando &amp;aacute;lgebra de Bool.&lt;/H2&gt;&lt;br /&gt;&lt;P&gt;Tal vez los programadores de lenguaje&lt;br /&gt;de ensamblador (assembly) est&amp;eacute;n familiarizados con esta forma.&lt;br /&gt;Se trata de utilizar la operaci&amp;oacute;n binaria “XOR” (o&lt;br /&gt;excluyente).&lt;/P&gt;&lt;br /&gt;&lt;P&gt;&lt;CODE&gt;a ^= b;&lt;BR&gt;b ^= a;&lt;BR&gt;a ^= b;&lt;/CODE&gt;&lt;/P&gt;&lt;br /&gt;&lt;P&gt;Alternativamente se puede hacer en una&lt;br /&gt;l&amp;iacute;nea:&lt;/P&gt;&lt;br /&gt;&lt;P&gt;&lt;CODE&gt;a ^= b ^= a ^= b;&lt;/CODE&gt;&lt;/P&gt;&lt;br /&gt;&lt;P&gt;Este c&amp;oacute;digo es la gloria. Aunque&lt;br /&gt;seg&amp;uacute;n tengo entendido no es portable, &amp;iexcl;as&amp;iacute; que no&lt;br /&gt;lo usen!&lt;/P&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-115061135456715766?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/115061135456715766/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=115061135456715766' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/115061135456715766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/115061135456715766'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2006/06/cmo-intercambiar-el-valor-de-dos.html' title='C&amp;oacute;mo intercambiar el valor de dos variables sin utilizar una tercera.'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29735925.post-115033809284246719</id><published>2006-06-14T23:19:00.010-03:00</published><updated>2009-09-24T01:38:07.348-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lenguaje C'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><title type='text'>Mezclando C con Assembly</title><content type='html'>Anteriormente titulado "Cómo mezclar C con código de ensamblador (assembly)"&lt;br /&gt;&lt;br /&gt;Copyright (c) 2006, 2007, 2008, 2009 Héctor Francisco Hernández &amp;lt;hectorfh@gmail.com&amp;gt;.&lt;br /&gt;Se otorga permiso para copiar, distribuir y/o modificar este documento bajo los términos de la Licencia de Documentación Libre de GNU, Versión 1.3 o cualquier otra versión posterior publicada por la Free Software Foundation; sin Secciones Invariantes ni Textos de Cubierta Delantera ni Textos de Cubierta Trasera. Una copia de la licencia se encuentra en http://www.gnu.org/copyleft/fdl.html.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;1. Introducción.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Existe una relación muy estrecha entre la programación en C y la programación en ensamblador. C fue creado para evitarle a los programadores del sistema operativo UNIX seguir escribiéndolo en ensamblador. Las ventajas de programar en C lo mismo que antes se programaba en ensamblador son obvias: portabilidad y legibilidad a través de un código bien estructurado. Sin embargo las partes del sistema en las que es necesario trabajar con características específicas del hardware no pueden ser escritas en C.&lt;br /&gt;&lt;br /&gt;En general hay dos estrategias para mezclar código en C con código en ensamblador. La primera consiste en compilar archivos escritos en C y ensamblar otros escritos en código de ensamblador para luego enlazarlos todos juntos. La segunda se trata de embeber código escrito en ensamblador dentro de código escrito en C a través de algún mecanismo que ofrezca el compilador usado. En este artículo se tratará sólo la primera estrategia.&lt;br /&gt;&lt;br /&gt;Aunque las ideas que aquí se exponen son útiles independientemente de cualquier plataforma, toda la nota presupone un sistema tipo UNIX (GNU en particular) en una arquitectura de procesador 80386 o superior.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;2. Construyendo programas.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Dado un conjunto de archivos en C, es necesario seguir ciertos pasos para obtener uno ejecutable.&lt;br /&gt;&lt;br /&gt;Para comenzar se deben incorporar los archivos de cabecera (los que se incluyeron mediante "#include"), expandir las macros y constantes (las que se declararon mediante "#define") y quitar el código que no satisfaga las condiciones para ser compilado (condiciones establecidas mediante "#ifndef", "#ifdef" o alguna otra estructura condicional del preprocesador). Esto en C se conoce como "preprocesar" el código fuente. En GNU/Linux los archivos "preprocesados" poseen la extensión ".i" y se generan con cualquiera de los siguientes comandos:&lt;br /&gt;&lt;br /&gt;$ cpp&amp;nbsp; ejemplo1.c &amp;gt; ejemplo1.i&lt;br /&gt;&lt;br /&gt;o&lt;br /&gt;&lt;br /&gt;$ cc -E ejemplo1.c &amp;gt; ejemplo1.i&lt;br /&gt;&lt;br /&gt;El próximo paso consiste en traducir el código en C preprocesado a código en ensamblador. Esto se hace del siguiente modo:&lt;br /&gt;&lt;br /&gt;$ cc -S ejemplo1.i&lt;br /&gt;&lt;br /&gt;Sin embargo también es posible obtener el código en ensamblador a partir del archivo "ejemplo1.c":&lt;br /&gt;&lt;br /&gt;$ cc -S ejemplo1.c&lt;br /&gt;&lt;br /&gt;En este último caso el compilador preprocesará el archivo automáticamente y al terminar la traducción eliminará "ejemplo1.i". De cualquier forma se obtendrá el mismo resultado, el archivo "ejemplo1.s".&lt;br /&gt;&lt;br /&gt;El tercer paso será ensamblar para conseguir código de máquina:&lt;br /&gt;&lt;br /&gt;$ as -o ejemplo1.o ejemplo1.s&lt;br /&gt;&lt;br /&gt;Alternativamente se puede hacer con el comando&lt;br /&gt;&lt;br /&gt;$ cc -c ejemplo1.s&lt;br /&gt;&lt;br /&gt;Así el compilador de C llamará al ensamblador automáticamente.&lt;br /&gt;&lt;br /&gt;Como resultado deberíamos obtener un archivo objeto con extensión ".o". Los archivos objeto contienen código de máquina en el que las direcciones de memoria no han sido definidas aún. Hay distintos formatos para estos archivos, entre ellos ELF (de Linux), COFF (algunos sistemas tipo UNIX), OMF (algunos sistemas de microchot).&lt;br /&gt;&lt;br /&gt;Llegado a este punto debo decir que se podría haber obtenido el archivo "ejemplo1.o" directamente de "ejemplo1.c" de la siguiente forma:&lt;br /&gt;&lt;br /&gt;$ cc -c ejemplo1.c&lt;br /&gt;&lt;br /&gt;Ahora sólo resta enlazar todos los archivos objeto para obtener el archivo ejecutable "programa-ejemplo":&lt;br /&gt;&lt;br /&gt;$ cc -o programa-ejemplo ejemplo1.o ejemplo2.o ejemplo3.o&lt;br /&gt;&lt;br /&gt;Para hacer esto también es posible llamar al enlazador directamente con el comando "ld". Aunque no recomiendo hacerlo ya que es necesario pasarle demasiados parámetros. Para ver un ejemplo visite el enlace sugerido al final del artículo al tutorial de gcc de Víctor Alberto González Barbone.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;La compilación separada.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Note que podríamos haber compilado todo junto con&lt;br /&gt;&lt;br /&gt;$ cc -o programa-ejemplo ejemplo1.c ejemplo2.c ejemplo3.c&lt;br /&gt;&lt;br /&gt;Sin embargo compilar todo en un único paso no es una buena opción. Cada vez que cambiaremos algunos de los archivos habrá que volver a compilar todos nuevamente, y eso llevará tiempo. Además, si ocurriere un error la compilación se suspenderá perdiendo los resultados intermedios.&lt;br /&gt;&lt;br /&gt;Para manejar la compilación de varios archivos por separado la herramienta adecuada es el "make". Explicar cómo utilizarlo excede los límites de este artículo. Nuevamente sugiero visitar los enlaces al final para más información.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;3. Mezclando código en lenguaje C con código en ensamblador.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Un ejemplo introductorio.&lt;br /&gt;&lt;br /&gt;Comenzaré mostrando un inútil programa que recibe como parámetro un número real y lo redondea. Aunque no entienda muy bien el código, no se preocupe, lo importante ahora es que comprenda la estructura.&lt;br /&gt;&lt;br /&gt;Se trata de tres archivos: "main.c", "redon.s" y "redon.h". El primero es el que contiene la función "main" escrita en C, ahí es donde comienza la ejecución. El segundo contiene la función "redon", que recibe como parámetro un número flotante, lo redondea y lo convierte en entero. En el tercero está el prototipo de "redon", necesario para que la función pueda ser llamada desde otros archivos.&lt;br /&gt;&lt;br /&gt;El archivo "main.c":&lt;br /&gt;&lt;br /&gt;#include "redon.h"&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int&lt;br /&gt;main (int argc, char *argv [])&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; float n;&lt;br /&gt;&amp;nbsp; int n_redon;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; if (2 != argc) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; fprintf(stderr, "Error: debe haber un parámetro\n");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 1;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp; n = (float) atof(argv [1]);&lt;br /&gt;&amp;nbsp; n_redon = redon(n);&lt;br /&gt;&lt;br /&gt;&amp;nbsp; printf("El número entero que más se aproxima a %f es %d.\n",&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; n, n_redon);&lt;br /&gt;&lt;br /&gt;&amp;nbsp; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;El archivo "redon.s":&lt;br /&gt;&lt;br /&gt;.text&lt;br /&gt;&lt;br /&gt;.globl redon&lt;br /&gt;redon:&lt;br /&gt;&amp;nbsp; flds&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x04 (%esp)&lt;br /&gt;&amp;nbsp; fistpl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x04 (%esp)&lt;br /&gt;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x04 (%esp), %eax&lt;br /&gt;&amp;nbsp; ret&lt;br /&gt;&lt;br /&gt;El archivo "redon.h":&lt;br /&gt;&lt;br /&gt;#ifndef REDON_H&lt;br /&gt;#define REDON_H&lt;br /&gt;&lt;br /&gt;int redon (float);&lt;br /&gt;&lt;br /&gt;#endif /* REDON_H */&lt;br /&gt;&lt;br /&gt;Observe el uso de las directivas ".text" y ".globl". La primera, aunque no parezca, indica que lo que sigue es código. La segunda, que "redon" podrá ser llamada desde funciones que estén en otros archivos objeto. Esto contrasta con las funciones en C, las cuales son globales por defecto a no ser que se indique lo contrario mediante la palabra clave "static".&lt;br /&gt;&lt;br /&gt;Para compilar y enlazar todo se deben ejecutar los siguientes comandos:&lt;br /&gt;&lt;br /&gt;$ cc -Wall -O -c main.c&lt;br /&gt;$ cc -c redon.s&lt;br /&gt;$ cc -o redondear main.o redon.o&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Las tres convenciones.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Para escribir funciones en ensamblador que puedan ser llamadas desde otras en C debe conocer tres convenciones. La primera tiene que ver con el pasaje de parámetros, la segunda con el retorno de valores y la tercera con la preservación de los valores en los registros.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;i. Pasaje de parámetros&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Cuando un programa se ejecuta el sistema operativo le asigna memoria para que pueda operar. Parte de la memoria asignada al programa es utilizada como una pila para almacenar las variables locales a las funciones (a excepción de las declaradas con la palabra clave "static"), los parámetros y algunas cosas más.&lt;br /&gt;&lt;br /&gt;En una arquitectura 80386 el registro "esp" (puntero de pila) es el que se encarga de guardar un puntero hacia el tope de la pila. Cuando se insertan datos en la pila a través de la instrucción "push" el tope de la pila ya no es el mismo, entonces el puntero de pila (que está guardado en el registro "esp") es cambiado automáticamente para que pueda continuar apuntando hacia el tope. Lo inverso ocurre cuando se quitan datos de la pila a través de la instrucción "pop". Cabe recordar que en una pila no es posible insertar o quitar datos de otro lugar que no sea su tope, de lo contrario no sería una pila.&lt;br /&gt;&lt;br /&gt;Si no está familiarizado con lo que estoy diciendo, probablemente tampoco esté familiarizado con la programación en ensamblador. Entonces sería muy conveniente que lea algún apunte introductorio acerca del tema. En Internet debe haber alguno corto. La programación en ensamblador excede los límites de este humilde artículo.&lt;br /&gt;&lt;br /&gt;Volviendo al punto, la importancia de la pila aquí es que es el mecanismo mediante el cual se pasan los parámetros a las funciones. Los parámetros son pasados de derecha a izquierda, es decir, primero se inserta en la pila el último parámetro, luego el penúltimo, y así se continúa hasta insertar finalmente el primero. La función que llama a otra es la que se encarga de colocar los parámetros en la pila y también de quitarlos. Esta es la convención en C, aunque existen otras convenciones en otros lenguajes en las cuales es la función llamada la que quita los parámetros de la pila.&lt;br /&gt;&lt;br /&gt;En un intento de aclarar el tema diré que para invocar a la función&lt;br /&gt;&lt;br /&gt;void f (int param1, int param2, int param3);&lt;br /&gt;&lt;br /&gt;con param1 = 3, param2 = 2 y param3 = 5 se debería escribir el siguiente código en C:&lt;br /&gt;&lt;br /&gt;f (3, 2, 5);&lt;br /&gt;&lt;br /&gt;y el siguiente en ensamblador:&lt;br /&gt;&lt;br /&gt;pushl&amp;nbsp;&amp;nbsp; $5&lt;br /&gt;pushl&amp;nbsp;&amp;nbsp; $2&lt;br /&gt;pushl&amp;nbsp;&amp;nbsp; $3&lt;br /&gt;call&amp;nbsp;&amp;nbsp;&amp;nbsp; f&lt;br /&gt;addl&amp;nbsp;&amp;nbsp;&amp;nbsp; $12, %esp&lt;br /&gt;&lt;br /&gt;Las tres primeras instrucciones colocan los parámetros en la pila. La cuarta llama a la función "f" y la quinta le adiciona doce al puntero de pila. Esto es porque los parámetros insertados ocupan doce bytes entre los tres (cuatro cada uno).&lt;br /&gt;&lt;br /&gt;Adicionarle y sustraerle al puntero de pila son maneras de liberar espacio y de hacer espacio en la pila respectivamente.&lt;br /&gt;&lt;br /&gt;Notará que luego de "push" y de "add" hay una "l". Esto no es propio del lenguaje ensamblador 80x86 de Intel. Sino que pertenece a la notación de AT&amp;amp;T, que es la adoptada por el ensamblador de GNU. Esta "l" significa que el parámetro de la instrucción es de 32 bits.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ii. Retorno de valores.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Según el tipo del valor retornado se procede de distinto modo.&lt;br /&gt;&lt;br /&gt;Para los tipos de datos predefinidos por el lenguaje la función llamada deposita el valor retornado en determinado registro. Luego la función que ha realizado el llamado asumirá que está en el registro convenido y accederá a él para obtenerlo. El registro que se utiliza depende del tipo de dato del valor retornado.&lt;br /&gt;&lt;br /&gt;A continuación listaré distintos tipos de datos y los registros utilizados:&lt;br /&gt;&lt;br /&gt;int / unsigned int / long / unsigned long -&amp;gt; eax&lt;br /&gt;short / unsigned short -&amp;gt; ax&lt;br /&gt;char / unsigned char -&amp;gt; al&lt;br /&gt;punteros -&amp;gt; eax&lt;br /&gt;float / double -&amp;gt; st (0)&lt;br /&gt;&lt;br /&gt;Las funciones que devuelven un tipo de dato definido por el usuario mediante "struct" o "union" cuentan automáticamente con un primer parámetro implícito adicional que indica la dirección de memoria en donde será copiado el valor devuelto.&lt;br /&gt;&lt;br /&gt;Por lo tanto se podría decir que las funciones:&lt;br /&gt;&lt;br /&gt;struct s f (int param1, int param2, int param3);&lt;br /&gt;&lt;br /&gt;y&lt;br /&gt;&lt;br /&gt;void f (struct s *retval, int param1, int param2, int param3);&lt;br /&gt;&lt;br /&gt;una vez traducidas al ensamblador tienen los mismos parámetros.&lt;br /&gt;&lt;br /&gt;Los tipos de datos definidos con "enum" se implementan del mismo modo que un numero entero, por lo tanto se devuelven copiando el valor al registro "eax".&lt;br /&gt;&lt;br /&gt;&lt;b&gt;iii. Preservación de los valores de los registros.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;En el momento de retorno de una función se espera que el valor de ciertos registros sea el mismo que en el momento de su llamado. Estos registros son ebp, esp, ebx, esi y edi. Por lo tanto si la función hará uso de ellos deberá guardarlos previamente y restaurarlos a sus valores originales luego, o asegurarse de cualquier otra forma que queden como los puso la función que hizo el llamado.&lt;br /&gt;&lt;br /&gt;Los registros eax, ecx, edx, eflags y los de la unidad de punto flotante (st (0), st (1), st (2), ..., st (7) y los registros de control y estado) pueden ser utilizados sin cuidado alguno. El resto de los registros del procesador (que no enumeraré) sólo puede ser modificado por el sistema operativo, por lo tanto se descarta su posibilidad de uso.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;4. Algunos consejos.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Llegando ya al final me gustaría mencionar algunas sugerencias.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;i. El compilador de C es una buena herramienta para estudiar ensamblador.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Escribir funciones en C y utilizar el compilador para traducirlas al ensamblador es una excelente manera de conseguir ejemplos de rutinas en este lenguaje. Debería ser uno de los primeros recursos para eliminar todas las dudas que surjan.&lt;br /&gt;&lt;br /&gt;Es aconsejable hacerlo activando la opción de optimización para obtener un buen código y las advertencias para detectar errores. El comando para hacer esto es el siguiente:&lt;br /&gt;&lt;br /&gt;$ cc -Wall -O -S ejemplo.c&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ii. Cuidado con el "decorado de nombres" en C++ y en algunos sistemas operativos.&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Es muy probable que algunos, tras leer este artículo, intenten mezclar ensamblador con C++ y las cosas no funcionen. Este lenguaje posee una propiedad denominada "decorado de nombre" (name decoration) o "planchado de nombre" (name mangling) que consiste en cambiar el nombre de las funciones cuando son traducidas al ensamblador. C++ necesita hacer esto para soportar la sobrecarga de funciones, las funciones miembro y otras características del lenguaje. Por lo tanto esperará que todos los nombres hayan sido decorados adecuadamente.&lt;br /&gt;&lt;br /&gt;A pesar de esto es posible invocar funciones cuyo nombre no ha sido "decorado" encerrando sus prototipos en un bloque precedido por la frase "extern "C" ".&lt;br /&gt;&lt;br /&gt;Para ilustrar con un ejemplo, el archivo "redon.h", para poder ser usado en C y también en C++, debería escribirse así:&lt;br /&gt;&lt;br /&gt;#ifndef REDON_H&lt;br /&gt;#define REDON_H&lt;br /&gt;&lt;br /&gt;#ifdef __cplusplus&lt;br /&gt;extern "C" {&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;int redon (float);&lt;br /&gt;&lt;br /&gt;#ifdef __cplusplus&lt;br /&gt;}&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;#endif /* REDON_H */&lt;br /&gt;&lt;br /&gt;El compilador de C en un popular sistema operativo no POSIX propenso a fallas realiza también un decorado según la convención de llamada de la función. Sin embargo consiste sólo en agregarle un guión bajo al nombre. Así, por ejemplo, el archivo "redon.s" debería sustituirse por el siguiente:&lt;br /&gt;&lt;br /&gt;.text&lt;br /&gt;&lt;br /&gt;.globl _redon&lt;br /&gt;_redon:&lt;br /&gt;&amp;nbsp;&amp;nbsp; flds&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x04 (%esp)&lt;br /&gt;&amp;nbsp;&amp;nbsp; fistpl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x04 (%esp)&lt;br /&gt;&amp;nbsp;&amp;nbsp; movl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x04 (%esp), %eax&lt;br /&gt;&amp;nbsp;&amp;nbsp; ret&lt;br /&gt;&lt;br /&gt;Pero "redon.h" no debería ser modificado.&lt;br /&gt;&lt;br /&gt;Para una mejor explicación del asunto se recomienda visitar los enlaces al final del artículo.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;iii. Utilice el comando "objdump" para desensamblar archivos binarios.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Este comando propio del UNIX desensambla archivos objeto y archivos ejecutables.&lt;br /&gt;&lt;br /&gt;Para hacerlo debe invocar el comando con la opción "-d":&lt;br /&gt;&lt;br /&gt;$ objdump -d ejemplo.o&lt;br /&gt;&lt;br /&gt;Consulte la documentación del sistema operativo para ver otras opciones que acepta el comando.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;iv. Utilice el comando "nm" para listar las funciones en un archivo binario.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;En los sistemas tipo UNIX el comando "nm" lista las funciones y variables que están dentro de un archivo objeto o un archivo ejecutable y a las que hacen referencia funciones dentro del archivo.&lt;br /&gt;&lt;br /&gt;Puede utilizarlo del siguiente modo:&lt;br /&gt;&lt;br /&gt;$ nm ejemplo.o&lt;br /&gt;&lt;br /&gt;Para aprender a leer el listado que genera sugiero recurrir a la documentación del comando.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;5. Enlaces que se sugiere visitar.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://iie.fing.edu.uy/%7Evagonbar/gcc-make/gcc.htm"&gt;Breve tutorial en español acerca del gcc de Víctor Alberto González Barbone.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Name_mangling"&gt;Artículo de la Wikipedia en inglés que explica con detalle de qué se trata el planchado de nombres.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://sig9.com/articles/att-syntax"&gt;Artículo en inglés de "vivek" que introduce la sintaxis de AT&amp;amp;T.&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29735925-115033809284246719?l=programacionbizarra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programacionbizarra.blogspot.com/feeds/115033809284246719/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29735925&amp;postID=115033809284246719' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/115033809284246719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29735925/posts/default/115033809284246719'/><link rel='alternate' type='text/html' href='http://programacionbizarra.blogspot.com/2006/06/cmo-mezclar-c-con-cdigo-de-ensamblador.html' title='Mezclando C con Assembly'/><author><name>Programador Bizarro</name><uri>http://www.blogger.com/profile/14350978008382875669</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
