Trucos Unix: ¿Como saber si un disco duro va a fallar con suficiente antelación?

El Proyecto SMARTMONTOOLS (http://smartmontools.sourceforge.net/), tiene herramientas de diagnostico proactivo, las cuales le van a decir si usted tiene una catastrofe inminente en sus manos, con respecto al almacenamiento. Por ejemplo, yo normalmente dejo que smartd (el demonio de monitoreo) se encargue el sólo de decidir como es la mejor manera de monitorear mis discos, por lo que yo sólo le digo que discos monitorear y a donde me debe enviar las alertas:

/etc/smartd.conf:
/dev/sda -H -m angelnegro@domain.com
/dev/sdb -H -m angelnegro@domain.com
/dev/sdc -H -m angelnegro@domain.com
/dev/sdd -H -m angelnegro@domain.com
/dev/sde -H -m angelnegro@domain.com
/dev/sdf -H -m angelnegro@domain.com

Ojo, usted puede tener discos SCSI (/dev/sd?), IDE (/dev/hd?), etc.
Lo más seguro es que cuando usted reciba una alerta usted quiere hacer diagnosticos más profundos en sus discos (si aún funcionan) para salir de dudas si estos están a punto de morir o si fué una falsa alarma; Allí es donde usted puede utilizar a una herramienta llamada ‘smartctl’ la cual puede ser incluida dentro de scripts más poderosos:

#!/bin/bash
declare -ar DISKS=(/dev/sda /dev/sdb /dev/sdc /dev/sdd
/dev/sde /dev/sdf /dev/sdg)
declare -r SMARTCTL="/usr/sbin/smartctl"
declare -ri ERROR_CODE=192
if [ ! -x $SMARTCTL ]; then
printf "Unable to execute %s\n" $SMARTCTL
exit $ERROR_CODE
fi
for disk in ${DISKS[@]}; do
printf "Testing: %s\n" $disk
$SMARTCTL -a -t long $disk
done

Y después puede buscar los resultados extendidos con un programita similar:

#!/bin/bash
declare -ar DISKS=(/dev/sda /dev/sdb /dev/sdc /dev/sdd
/dev/sde /dev/sdf /dev/sdg)
declare -r SMARTCTL="/usr/sbin/smartctl"
declare -ri ERROR_CODE=192
if [ ! -x $SMARTCTL ]; then
printf "Unable to execute %s\n" $SMARTCTL
exit $ERROR_CODE
fi
for disk in ${DISKS[@]}; do
printf "Testing: %s\n" $disk
$SMARTCTL -a -l error -H $disk
done

¡Esta es una de las herramientas que no deberían faltar en su arsenal!

Escuela Latinoamericana de Redes: Algunos recuerdos

Me conseguí estas fotografías cuando buscaba entre unos documentos que necesitaba enviar; Son fotografías de 7 años atrás, cuando tuve la oportunidad de ir a Brasil, Rio de Janeiro, a dar clases en el evento Walc 1998.

walc1998 Rio De Janeiro
(si mucho más delgado en la foto)

Aún recuerdo que hablé de Unix y de Perl con CGI. Pero lo mejor fué la experiencia de el viaje, justo después de recien graduarme en la Universidad (si, el tema de la edad sale otra vez a flote, jejejeje) y la gente genial con la que compartí esos momentos.

Recuerdo que había gente de toda Latinoamerica: Venezuela, Colombia, Perú, México, Brasil, Argentina, Chile, Uruguay, Cuba…

También recuerdo una de mis metidas de pata, cuando empecé en esto de dar clases; Estabamos hablando de como preparar una base de datos con MySQL y en eso dije algo como lo siguiente:

Yo: Bueno señores, vamos a continuar con la instalación de la base de datos.
Clase: OK
Yo: Ahora, vayan a X-Window y abran una concha y escriban lo siguiente

No sé porqué me dió por decir ‘concha‘ en vez de ‘shell‘. Cuando me di cuenta de mi error, habían un montón de Uruguayos, Argentinos y Chilenos muertos de la risa por mi torpeza (si aún no ha caido, concha = vagina). Allí aprendí a utilizar Castellano ‘neutral’ (aunque mis Venezolanismos con el tipico ‘chamo’ aún sigue saliendo).

walc1998 Rio De Janeiro
(yo, Raúl Echeverria, no recuerdo, Juan Carlos Alonzo, Sylvia Cadenas)

Curiosamente, uno de los organizadores, Hermanno Pietrosemoli, tiene una presentación en la cual habla de sus experiencias estos últimos 15 años en el área de comunicaciones inalámbricas, allí mencionan a WALC 98. Sin embargo si quiere saber más de La Escuela Latinoamericana de Redes, entonces no deje de visitar su sitio web, tienen información muy interesante allí sobre la organización y de como fomenta el intercambio de conocimiento entre instituciones de Latinoamerica.

En mi opinión, es uno de los pocos eventos que fomentan la cooperación Latinoamericana a nivel de técnología y Universidades.

Echando código: Como ordenar una lista simplemente enlazada sin crear una estructura adicional

Bueno, de nuevo otra pregunta, la cual busca ver si usted puede manejar algoritmos complejos:

¿Como se puede ordenar de atrás para adelante una lista simplemente enlazada, sin crear estructuras de datos adicionales?

Muchas compañias preguntan acerca de listas simplemente enlazadas ya que su implementación es sencilla y se puede realizar en el tiempo programado para una entrevista; Este problema tiene muchas soluciones, una que me gustó bastante (y de la cual no me atribuyo la solución) la encontré en un enlace en la Universidad de Stamford, toda ella llena de problemas interesantes de listas, es la de los 3 apuntadores.

Primero, una implementación básica de un nodo de la lista:

   1:/**
2: * This class models a 'String' node on a list.
3: * @author Jose V Nunez Zuleta
4: * @version 0.1 - 03/07/2005
5: * Blog: El Angel Negro - http://elangelnegro.blogspot.com
6: * License: GPL
7: */
8:public class Node {
9:
10: protected String value;
11: protected Node next;
12:
13: /**
14: * Parametric constructor
15: * @param value
16: * @since 0.1
17: */
18: public Node(String value) {
19: this.value = value;
20: }
21:
22: /**
23: * Show the internal state of the object
24: * @return String
25: */
26: public String toString() {
27: if (next != null) {
28: return "{" + value + "," + next.value + "}";
29: } else {
30: return "{" + value + ", null}";
31: }
32: }
33:}

Y luego el código que hace la ordenación de atrás para delante:

   1:/**
2: * Common <a href="http://cslibrary.stanford.edu/105/LinkedListProblems.pdf">algorithms</a>
3: * for single linked lists
4: * @author Jose V Nunez Zuleta
5: * @version 0.1 - 03/07/2005
6: * Blog: El Angel Negro - http://elangelnegro.blogspot.com
7: * License: GPL
8: *
9: */
10:public class Lists {
11:
12: /**
13: * Stores the arguments in a list and performs list manipulations
14: * @param args - List of arguments to convert
15: * @throws Exception If list is empty
16: */
17: public static void main(String [] args) {
18:
19: if (args == null) {
20: throw new
21: IllegalArgumentException("Provide some nodes");
22: }
23:
24: if (args.length == 0) {
25: throw new
26: IllegalArgumentException("Provide some nodes");
27: }
28: int len = args.length;
29: Node head = new Node(args[0]);
30: for (int i = 1; i < len; i++) {
31: append(head, new Node(args[i]));
32: }
33: iterate(head);
34: head = reverse(head);
35: iterate(head);
36: }
37:
38: /**
39: * Show the contents of the single linked list.
40: * @param head
41: */
42: public static void iterate(Node head) {
43: Node current = head;
44: while (current != null) {
45: System.out.print(current);
46: if (current.next != null) {
47: System.out.print(" ");
48: }
49: current = current.next;
50: }
51: System.out.println();
52: }
53:
54: /**
55: * Add elements at the end of the list
56: * @param head List head
57: * @param node Node to add at the end.
58: */
59: public static void append(Node head, Node node) {
60: Node current = head;
61: while (current.next != null) {
62: current = current.next;
63: }
64: current.next = node;
65: node.next = null;
66: }
67:
68: /**
69: * Reverse a single linked list without using an additional structure.
70: * This algorithm uses three pointers (bac, middle and front) to keep
71: * track of the changes.
72: * This method is not recursive.
73: * @param head Head of the list
74: * @return The new head of the list.
75: */
76: public static Node reverse(Node head) {
77: if (head == null) {
78: return head;
79: }
80: Node middle = head;
81: Node front = middle.next;
82: Node back = null;
83: while(true) {
84: middle.next = back;
85: if (front == null) {
86: break;
87: }
88: back = middle;
89: middle = front;
90: front = front.next;
91: }
92: return middle;
93: }
94:}

Ojo, antes que salga un purista con que mi implementación de una lista es muy tosca, si eso ya lo sé. De hecho no está bien ‘orientada a objeto’ y modela muy cerca lo que usted haría en un lenguaje como C.

¿Como la mejoraría?

Aqui tiene el código como de costumbre.

Trucos Unix: ¿Como saber si un demonio está arriba o no con SNMP?

Usted tiene el siguiente problema: Tiene un par de demonios que quiere monitorear, pero no puede revizar directamente si están arriba ya que o hablar el protocolo nativo es complicado (por ejemplo para monitorear NTP desde Perl quizas tenga que instalar Net::NTP pero eso le pide Perl 5.8.0 y usted tiene 5.6.1), el demonio no va a hablar directamente con usted (por ejemplo un ACL para evitar que el demonio sea hackeado) o simplemente el demonio no acepta conexiones (por ejemplo un programa en Perl o Java que corre todo el tiempo pero no escucha en ningún puerto).

¿Todo está perdido?. No, si usted tiene la suerte de que puede correr Net-SNMP en la máquina en cuestion, entonces sólo tiene que agregar una línea en la configuración de el agente para ver si el demonio está arriba. Ya antes yo les habia hablado de Net-SNMP por acá y hasta les había dejado un archivo de configuración de referencia.

Una ventaja de monitorear demonios de esta manera es que el protocolo de SNMP está especialmente diseñado para consultar una cantidad larga de dispositivos y valores, por lo que la sobrecarga de datos en la red debería ser menos que preguntar directamente a los servicios nativos; Lo otro es que también usted se ahorra el trabajo de hablar varios protocolos y le deja el trabajo a SNMP de ver si el demonio está arriba (si, ya se, usted siempre puede ver si el puerto está abierto con un simple socket peo esa no es una transacción de verdad, además de que usted tiene que echar el código). En este caso, es una virtud el ser perezoso…

El algoritmo va de la siguiente manera:

  1. Haga una transferencia de la zona de su servidor de DNS (o haga un port scanning de toda la red). En mi opninión es más rápido la transferencia ya que así solamente contactamos a los servidores que realmente están registrados (usted tiene un SA que mantiene al dia el DNS, ¿no es asi?)
  2. Por cada registro tipo A (ignore CNAMES, PTR, MX, etc) haga una consulta de el OID de el servicio a monitorear (especifico de el agente Net-SNMP). La razón es que el indice cambia dependiendo de como nuestro SA haya configurado el archivo ‘snmpd.conf’. Si no tiene indice es que el servicio no está siendo monitoreado por el agente, asi que ignore esta maquina.
  3. Si el indice existe, entonces obtenga la bandera de error. Si es igual a 1, es que el demonio no estaba corriendo, asi que reporte el error.

Hacer este programa me tomó 1 hora, mientras escuchaba Apocalyptica y limpiaba las cagadas, por lo que no es el fin del mundo:

   1:#!/usr/bin/perl
2:
3:use Net::DNS;
4:use Net::SNMP;
5:use strict;
6:
7:use constant PORT =>
8: 161;
9:use constant BASE_OID =>
10: '.1.3.6.1.4.1.2021.2';
11:use constant INDEX_OID =>
12: BASE_OID . '.1.2';
13:use constant STATUS_OID =>
14: BASE_OID . '.1.100';
15:use constant VERSION =>
16: 2;
17:use constant UNKNOWN_INDEX =>
18: -1;
19:
20:use constant ERROR_CODE =>
21: 192;
22:
23:use constant OK_CODE =>
24: 0;
25:
26:if ((scalar(@ARGV)) != 4) {
27: &usage();
28: exit ERROR_CODE;
29:}
30:
31:my $res = Net::DNS::Resolver->new;
32:$res->nameservers($ARGV[0]);
33:# Perform a DNS zone transfer
34:my @zone = $res->axfr($ARGV[1]);
35:foreach my $rr (@zone) {
36: if ($rr->type eq "A") {
37: my $name = $rr->name;
38: printf "%s\n", $name;
39: my ($session, $error) = Net::SNMP->session(
40: -hostname => $name,
41: -community => $ARGV[3],
42: -version => VERSION,
43: -port => PORT
44: );
45: my $result = $session->get_table(
46: -baseoid => INDEX_OID
47: );
48: if (! defined $result) {
49: printf "\t[INFO]: No response from, %s\n", $name;
50: } else {
51: my $index = UNKNOWN_INDEX;
52: foreach my $key (keys %${result}) {
53: # The index position will depend of the order given by the SA,
54: # on the snmpd.conf file, so it is better so look for it!
55: if ($$result{$key} eq "$ARGV[2]") {
56: my @tokens = split('\.', $key);
57: $index = $tokens[scalar(@tokens)-1];
58: }
59: }
60: # It is being monitored?
61: if ($index == UNKNOWN_INDEX) {
62: print "\t[INFO]: Daemon not being monitored!\n";
63: } else {
64: # Now get the status of the daemon
65: my $key = STATUS_OID . "\.$index";
66: my $result2 = $session->get_request(
67: -varbindlist => [$key]
68: );
69: if (! defined $result2) {
70: printf "\t[ERROR]: Unable to poll %s\n", $name;
71: } else {
72: if ($$result2{$key} == 0) {
73: print "\t[INFO]: Service is OK\n";
74: } else {
75: printf "\t[WARNING]: Service is not OK on '%s', status=%s\n", $name, $$result2{$key};
76: }
77: }
78: }
79: }
80: my $error_message = $session->error;
81: if ($error) {
82: printf "\t[ERROR]: %s, %s\n", $name, $error;
83: }
84: if (defined $session) {
85: $session->close;
86: }
87: }
88:}
89:exit OK_CODE;
90:
91:sub usage() {
92:print << "EOF";
93:Usage mode:
94: quick_test.plx nameserver dnsdomain daemonname snmpcommunity
95:
96:Where:
97: nameserver - DNS from where we will pull the DNS zone
98: dnsdomain - Full DNS domain to check
99: daemonname - The process to check for (ntpd, ssh)
100: snmpcommunity - The SNMP community string
101:
102:To read the documentation of the script, do the following:
103:
104:perldoc quick_test.plx
105:
106:EOF
107:}
108:__END__
109:
110:=head1 NAME
111:
112:quick_test.plx - A quick script to check the status of programs running on a Linux server,
113:asuming than the DNS server list is up to date and than the Net-SNMP daemon is running!
114:
115:=head1 DESCRIPTION
116:
117:=head2 DNS SERVER CONFIGURATION
118:
119:Make sure you can do zone transfers from your Perl client; Asuming than '10.1.50.254' is your IP address:
120:
121:allow-transfer { 127.0.0.1; 10.1.50.254; };
122:
123:Our you will get the following error:
124:
125: Mar 1 17:40:18 XXX named[28161]: client 10.1.50.254#59195: zone transfer 'elangelnegro.blogspot.com/IN' denied
126:
127:=head2 SNMP CLIENT CONFIGURATION
128:
129:Make sure than the monitoring of the SNMP daemon is enabled on all the servers (/etc/snmp/snmp.conf):
130:
131:# snmpwalk -v 2c -h localhost public .1.3.6.1.4.1.2021.2
132:proc snmpd 1 1
133:proc sshd
134:proc syslogd 1 1
135:proc ypbind 10 1
136:proc portmap 1 1
137:proc ntpd 1 1
138:proc crond 1 1
139:
140:=head1 AUTHOR
141:
142:Jose V Nunez Zuleta
143:
144:=head1 BLOG
145:
146:El Angel Negro - http://elangelnegro.blogspot.com
147:
148:=head1 LICENSE
149:
150:GPL
151:
152:=cut

La salida de ejemplo:

[root@XXX lucifer]# ./quick_test.plx server dnsdomain ntpd community-string
server1.dnsdomain
[INFO]: Daemon not being monitored!
server2.dnsdomain
[INFO]: No response from, server2.dnsdomain
server2.dnsdomain
[INFO]: No response from, server2.dnsdomain
server3.dnsdomain
[INFO]: No response from, server3.dnsdomain
server4.dnsdomain
[INFO]: No response from, server4.dnsdomain
server5.dnsdomain
[INFO]: Service is OK
server6.dnsdomain
[INFO]: Service is OK
……

¿Como lo puede mejorar?

Puede bajarselo desde acá.

Echando código: Escribir un servidor sencillo en Java

Esta es una típica pregunta de entrevista de programación: Escriba un servidor sencillo en Java, el cual esté en capacidad de atender a varios clientes a la vez.

El truco aqui es abstraer la definición de una tarea; El servidor recibe la nueva conexión (un Socket) y es allí en donde deberíamos crear una nueva hebra de ejecución (Thread) para atender al cliente. Por supuesto, como el tiempo es corto no le van a pedir que maneje los siguientes casos:

  • Seguridad (como controlar quien se conecta)
  • Optimizaciones: Piscinas de hebras de ejecución (thread pools)
  • Registro de eventos
  • Inicialización, finalización del servidor

Pero el que no le pidan la implementación no significa que usted al menos no deberia al menos saber como hacerlo (le pueden preguntar la idea general).

El sitio de Java tiene tutoriales extremadamente completos sobre Sockets, así que esta vez yo sólo me voy a limitar a colcarles el código aqui y un enlace para que se lo baje. Yo utilicé un número mayor que 1024 en el puerto de manera que usted pueda correr este demonio sin ser root.

Veamos entonces la división de tareas; Primero definimos una tarea la cual es la que actualmente hace el trabajo:

   1:import java.io.IOException;
2:import java.io.OutputStream;
3:import java.io.InputStream;
4:import java.io.PrintWriter;
5:import java.io.BufferedReader;
6:import java.io.InputStreamReader;
7:
8:import java.net.Socket;
9:/**
10: * This class takes care of a client connecting to the server.
11: * License: GPL
12: * Blog: El Angel Negro - http://elangelnegro.blogspot.com
13: * @author Jose V Nunez Z
14: * @version 0.1 - 02/28/2005
15: */
16:public class Task implements Runnable {
17: private Socket socket;
18: private Server server;
19:
20: /**
21: * Class constructor
22: * @param socket Client Socket
23: * @since 0.1
24: */
25: public Task(Socket socket, Server server) {
26: this.socket = socket;
27: this.server = server;
28: }
29:
30:
31: /**
32: * Method called by the current executing thread
33: * @since 0.1
34: */
35: public void run() {
36: PrintWriter out = null;
37: BufferedReader in = null;
38: try {
39: out = new PrintWriter(
40: socket.getOutputStream(),
41: true
42: );
43: in = new BufferedReader(
44: new InputStreamReader(
45: socket.getInputStream()
46: )
47: );
48: String line = null;
49: while( (line = in.readLine()) != null ) {
50: /*
51: * Now take the input and write it back to the
52: * client.
53: */
54: out.write(line);
55: out.write("\n");
56: if (line.equals(".")) {
57: break;
58: }
59: }
60: line = null;
61: } catch (IOException ioexp) {
62: ioexp.printStackTrace();
63: } finally {
64: if (out != null) {
65: try {
66: out.close();
67: } catch (IOException ignore) {
68: // Empty
69: };
70: }
71: if (in != null) {
72: try {
73: in.close();
74: } catch (IOException ignore) {
75: // Empty
76: };
77: }
78: if (socket != null) {
79: try {
80: socket.close();
81: } catch (IOException ignore) {
82: // Empty
83: };
84: }
85: server.decrementClient();
86: }
87:
88: }
89:}

Y el servidor el cual escucha por nuevas conexiones y despacha nuevas tareas:

   1:import java.io.IOException;
2:import java.net.ServerSocket;
3:import java.net.Socket;
4:/**
5: * This class shows how to create a simple Echo server with TCP Sockets.
6: * License: GPL
7: * Blog: El Angel Negro - http://elangelnegro.blogspot.com
8: * @author Jose V Nunez Z
9: * @version 0.1 - 02/28/2005
10: */
11:public class Server {
12:
13: private int clients = 0;
14:
15: /**
16: * Default port to be used by the server
17: */
18: public static final int PORT = 1973;
19:
20: protected synchronized void incrementClient() {
21: clients++;
22: }
23:
24: protected synchronized void decrementClient() {
25: clients--;
26: }
27:
28: /**
29: * Command line processing
30: * @param args - ignored
31: * @throws IOException
32: * @since 0.1
33: */
34: public static void main(String [] args) throws IOException {
35: ServerSocket server = null;
36: try {
37: server = new ServerSocket(PORT);
38: System.out.println("Started echo server on port: "
39: + PORT);
40: Server instance = new Server();
41: while(true) {
42: Socket socket = server.accept();
43: instance.incrementClient();
44: System.out.println("Connected client #: "
45: + instance.clients);
46: Task task = new Task(socket, instance);
47: Thread thread = new Thread(task);
48: thread.start();
49: }
50: } catch (IOException ioexp) {
51: throw ioexp;
52: } finally {
53: try {
54: if (server != null) {
55: server.close();
56: }
57: } catch (IOException ignore) {
58: // Empty
59: }
60: }
61: }
62:}

Aquí está el enlace para que se lo baje.

Rompecabezas malditos: Escogiendo el color correcto de un par de medias

Socks puzzle

Vaya, ya me acusaron también de sádico por esto de los rompecabezas. Voy a seguir a ver que es lo siguiente que sale por este Blog 😉

Este rompecabezas además de ser divertido, es útil ya que seguramente lo va a ayudar a no meter la pata cuando este escogiendo el color de un par de medias:

Usted tiene 8 medias rojas y 11 medias azules en una gaveta. ¿Cual es el mínimo número de medias que debe sacar para tener un par con el mismo color?

Pienselo un poco. No es tan dificil, haga un dibujo en un papel y cuente.

El truco aqui es contar. Este es un arbol binario (yo sólo necesito un par de medias, ¿no es así?) asi que usted puede jugar con todas las combinaciones si utiliza un arbol de decisiones:

Si decimos que R=media roja, y A=media azul entonces tenemos lo siguiente:

Arbol de medias

O sea, que el mínimo de medias que necesitamos es 3, ¡en cualquier caso!

¡Ahora más nunca lo van a fastidiar por tener medias de colores distintos! 🙂

Echando código: ¿Como crear una clave numérica de una palabra?

Suponga que tiene el siguiente problema: A usted le dan una lista de simbolos de la bolsa: SUNW, IBM, RHAT y le piden que los almacene internamente como una clave; Idealmente deberíamos generar un identificador único por cada palabra.

Bueno, en Java podemos llamar al método de la clase String llamado ‘hashcode’; Un hash no es más que una función de transformación que nos permite convertir una cosa en otra, usando un algoritmo conocido. En este caso logramos mapear nuestra cadena a un número único. Los Hashes no son perfectos, ya que pueden generar lo que se llaman colisiones (dos entradas producen el mismo hash) y es allí en donde entran varios algoritmos para manejar esos casos.

Aquí les dejo un código que utiliza la implementación interna de Java de ‘hashcode‘ y otro algoritmo el cual se aprovecha de la conversión de cada caracter en el objeto String a un char, para luego darle un peso dada su posición en la cadena (con lo cual obtenemos un número único).

Usted debe tener mucho cuidado al escoger una función Hash; Una buena función es aquella que tiene pocas colisiones, y sólo los matemáticos pueden demostrar con estadística si una función es buena. Yo en su caso mejor y utilizo un algoritmo que ya haya sido probado por alguien con anterioridad.

El código:

   1:/**
2: *
3: * You are given a list of Compay Ticker symbols. You want to save them as
4: * a unique code on a data structure.
5: * Hints: There are two solutions, one implies a hash and the other an array
6: * @author Jose V Nunez Z
7: * @version 0.1 - 02/28/2005
8: * License: GPL
9: * Blog: El Angel Negro - http://elangelnegro.blogspot.com
10: */
11:public class TickerCode {
12:
13: /**
14: * Command line entry point
15: * @param args - ignored
16: */
17: public static void main(String [] args) {
18: String [] symbols = {
19: "RHAT",
20: "IBM",
21: "SUNW",
22: "MSFT",
23: "TFSM"
24: };
25: int len = symbols.length;
26: for (int i = 0; i < len; i++) {
27: System.out.println(
28: "Code for symbol '" +
29: symbols[i] +
30: "'" +
31: " is " +
32: getCodeArray(symbols[i]) +
33: ", " +
34: getCodeHash(symbols[i])
35: );
36: }
37:
38: }
39:
40: /**
41: * The formula to get it using a Hash and a String:
42: *
43: * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
44: *
45: * Where s[n] is the char on the position 'n' for the String 's'
46: * 'n' is the length of the String 's'
47: * You repeat this process for all the chars on the String!
48: * @param symbol Simbol to convert
49: * @return int The code
50: */
51: private static int getCodeArray(String symbol) {
52: int code = 0;
53: char [] chars = symbol.toCharArray();
54: int len = chars.length;
55: for (int i = 0; i< len; i++) {
56: code += (chars[i]*31^(len-i));
57: }
58: return code;
59: }
60:
61: /**
62: * Uses the internal String hashcode
63: * @param symbol Simbol to convert
64: * @return int The code
65: */
66: private static int getCodeHash(String symbol) {
67: return symbol.hashCode();
68: }
69:
70:}

Una corrida de ejemplo:

[josevnz@XXX Ticker]$ javac TickerCode.java -d .
[josevnz@XXX Ticker]$ java TickerCode
Code for symbol ‘RHAT’ is 9391, 2514153
Code for symbol ‘IBM’ is 6690, 72276
Code for symbol ‘SUNW’ is 10313, 2556843
Code for symbol ‘MSFT’ is 9738, 2375924
Code for symbol ‘TFSM’ is 9730, 2572364

Y se lo puede bajar de aquí.

Rompecabezas malditos: Encontrar la esfera defectuosa en un grupo, usando una balanza

Balance puzzle

Veo que han habido de todo tipo de reacciones con los rompecabezas; Para todos aquellos que opinaron les traigo uno nuevo el cual tiene muchisimas variantes:

Imaginese el siguiente problema: Le dicen que usted tiene 8 esferas las cuales lucen identicas, pero una de ellas es defectuosa (es más liviana). Usted cuenta con una balanza a la cual se le pueden meter monedas y cada vez que pesa algo, debe pagar por el servicio. Diga cual es la manera más economica (menor número de pesadas) de pesar las esferas para encontrar a la esfera defectuosa.

Pista: Piense en como puede agrupar a las esferas antes de pesarlas. No siga leyendo, intentelo.

Solución: La última clave es importante. Usted puede empezar diciendo una solución sub-optima para luego refinarla, por ejemplo dividir las esferas en 2 grupos de 4; Uno de ellos va a ser más liviano, asi que toma ese grupo y lo divide en 2 grupos de 2, saca a las dos más livianas y luego vuelve a pesar 1 a la izquierda y 1 a la derecha. La más liviana es entonces la defectuosa.

Pero, ¿Se puede hacer en menos de 3 intentos?

Si se puede. Usted no tiene que pesar a todas las esferas, siga estos pasos:

  1. Haga 3 grupos: 1 grupo de 2, 2 grupos de 3 : {2, 3, 3}
  2. Pese los dos grupos de 3 {3, 3}. Si pesan lo mismo entonces ahora pese las dos esferas que le quedaron por pesar (1 a la izquierda, otra a la derecha). Allí la más liviana es la defectuosa y usted tardó sólo dos intentos.
  3. Si los dos grupos de 3 no pesan lo mismo, tome el grupo más liviano (la defectuosa está allí), deje una afuera y pese una a la izquierda y otra a la derecha {1 , 1, 1}. Si pesan lo mismo significa que la defectuosa está afuera de la balanza, o sea que le tomó sólo dos intentos.
  4. Si una de las dos esferas pesó menos que la otra esa es la defectuosa y entonces le tomó sólo dos intentos.

¿Que le pareció? 🙂

Rompecabezas malditos: ¿Como saber el salario promedio sin decir tu sueldo?

Dinner for three
Imaginese que usted va con otro 2 compañeros de trabajo a un restaurante y ¡alguien tiene la brillante idea de calcular el salario promedio de los 3!. El problema es que usted no quiere que nadie sepa su salario, ni los demas quieren revelar los suyos. No sirve colocar los salarios escritos en una servilleta para que alguien los lea, ya que además de el riesgo de que alguien reconozca la escritura, es probable que alguien sepa el rango de salarios para una posición y “adivine” el rango de una de las personas, por consiguiente el de la otra también sale (obviamente usted conoce su salario o es un pendejo :)).

Cada una de las personas se puede comunicar con los otros dos compañeros, asi que la pregunta es ¿qué puede hacerse para sacar el salario promedio sin revelar el salario de cada quien?

Pienselo un poco y siga leyendo después de que lo haya intentado…

Solución: El truco aqui es disfrazar el número para que nadie lo reconozca. Por ejemplo usted podría hacer esto, asumiendo que los sueldos son A, B, C:

  1. A’ = A + K (donde K es una constante arbitraria, preferiblemente más grande que A)
  2. B’ = B + W (donde W es una constante arbitraria, preferiblemente más grande que B)
  3. Z = A’ + B’ (Esto lo puedem sumar A o B).
  4. Luego A y B le dicen a C que a Z le reste K y W. De esa manera ni A ni B saben cuanto gana cada uno y C no tiene tampoco manera de averiguar cuanto ganan los otros dos… Llamemos a ese número W = Z – K -W
  5. C le suma su salario a W y lo divide entre 3 => Primedio = ( C + W ) / 3

¡Así que ya sabe que hacer cuando quiera saber el salario promedio de sus amigos, sin ser indiscreto :)!

Rompecabezas malditos: !Pagando con lingotes de oro!

Gold Bar

Usted tiene el siguiente problema: En su casa están haciendo trabajos de reparación y hace dos días que contrató a un experto albañil, el cual ha decidido cobrarle a usted por sus servicios a diario. Usted y el albañil han acordado que los trabajos van a tomar exactamente 7 días en ser realizados, y para pagarle usted lo hará con una barra de oro la cual tiene 7 divisiones (imaginese una barra de chocolate de Savoy, pero de oro). El problema es que usted (por alguna misteriosa razón supersticiosa) sólo puede picar la barra 2 veces en cualquiera de sus divisiones marcadas. Al final de el trabajo el albañil va a tener en su poder toda la barra de oro.

Teniendo en cuenta esa limitación, ¿Es posible pagarle al albañil diariamente? De ser así, ¿como puede hacerlo?

Pienselo un poco, y cuando este listo vuelva a leer.

Pista: ¿Que pasa cuando usted va a comprar una Malta Caracas (la cual cuesta Bs. 500) y usted paga con un billete de 1000?

Solución: La última pista es reveladora. Cuando usted paga de más, usted recibe cambio (el excedente), ¿no?. El algoritmo quedaría así (tome papel y lapiz y dibuje los cuadritos, a mi me ayudó que jode):

  1. Día 1: Pique un lingote de tamaño 1 y deselo al albañil. Ya resolvió el peo por el día de hoy, el albañil tiene un lingote de tamaño 1 y usted tiene un lingote de tamaño 6.
  2. Dia 2: Pique un lingote de tamaño 2, deselo al albañil y pidale el lingote de tamaño 1 que le dió ayer. Ahora el albañil tiene un lingote de tamaño 2 y usted tiene uno de tamaño 1 y otro de tamaño 4. Note que ya no podemos picar más lingotes.
  3. Dia 3: Pagele con el lingote de tamaño 1. Ahora usted aún tiene el lingote de tamaño 4 y el albail tiene dos piezas separadas, una de tamaño 1 y otra de tamaño 2.
  4. Dia 4: Paguele al albañil con un un lingote de tamaño 4 y pida de vuelta los lingotes de tamaño 2 y 1; El al albañil ahora tiene un lingote de tamaño 4 y usted tiene dos, uno de tamaño 1 y otro de tamaño 2.
  5. Dia 5: Pagele con el lingote de 1 otra vez. Ahora el albañil tiene dos lingotes, uno de tamaño 1 y el otro de tamaño 4.
  6. Dia 6: Pagele con el lingote de tamaño 2 y pida de vuelta el lingote de tamaño 1. El albañil tiene ahora el lingote de tamaño 4, y el de tamaño 2. Usted el de tamaño 1.
  7. Dia 7: Paguele con el último lingote que le queda de tamaño 1. El albañil ahora tiene todas las piezas y usted está pelando bolas 🙂

Espero le haya gustado :).