domingo, abril 28, 2013

Expo Construccion 2013


Hola [email protected] ayer visite la expo y quisiera comentar brevemente mi experiencia:

Lo primero la entrada fue relativamente rápida (fluido), debes llevar listos 2000 colones para el parqueo y 2000 mas por cada persona que quiera entrar al recinto.

La expo resulta bastante grande, en mi caso solamente buscaba una opción de préstamo hipotecario para lote y por el hecho de tener un contrato con el Invu, necesito que el crédito hipotecario sea de una entidad publica (para que el Invu acepte una hipoteca en segundo grado), así que aquí mis impresiones:

Solicite crédito en dolares porque gano en esa moneda, primero visite el banco popular; este me resulto el menos conveniente a pesar que tiene la menor cuota, 30 años, tienen una tasa variable (aunque no es la pasiva dicen que es una mas estable, sin techo ni piso) mas un 3% fijo. Como dije es la menor pero por ser 30 años se termina pagando poco menos del triple, se hacen pagos al saldo o se cancelan los créditos con antelación antes de los 5 años, se cobra un 3%. Después de ese periodo se puede cancelar o adelantar sin problema.

Bancredito y BCR, resultan muy similares; uno con 20 y el otro con 25, cubren un 80% del avaluo; mismas políticas para pagos al saldo o cancelación que el popular, la tasa es un poquito mejor en el BCR (pero el periodo es mayor).

Por ultimo la que yo pienso resulta la mejor opción es el Banco de CR, tiene la menor cuota, periodo de 20 años y puedes hacer pagos al saldo o cancelación desde el inicio del periodo sin penalidad; cubre un 80% de la deuda por crédito hipotecario, pero con uno fiduciario (con un fiador) te prestan hasta un 90% del valor del lote.

Bueno esta fue mi apreciación, existen muchos proyectos de construcción y materiales que apenas vi; en particular a la pocas que le tire un ojo, los proyectos listos resultan demasiado costosos.

Un saludo y suerte,
J

jueves, abril 18, 2013

Clase Download alpha


En esta ocasión quiero entregarles uno de los códigos mas interesantes del siguiente ejercicio, el administrador de descargar.

Este administrador de descargas al estilo del viejo FlashGet, nos muestra una primera clase; Download.

Esta clase primeramente nos muestra su "signature", es un objeto observable y puede ser corrido paralelamente.

Seguidamente nos muestra el tamaño máximo que el buffer va leer, 1 kb por lectura para el "stream".

Después vemos el Status, muy auto descriptivo.

Y las propiedades de la clase, el url a descargar, el tamaño del archivo remoto a descargar, "downloaded" almacena la cantidad de bytes leídos, el estado actual de la descarga y por ultimo un valor opcional "baseDirectory" que se refiere al directorio base de donde almacenar los archivos a descargar.

A continuación, encontraremos una serie de métodos que nos develan el estado o disparan nuevos estado a la descarga.

Una vez creada la descarga, se puede invocar al método "startDownload" cuando desee iniciar la descarga.

Por ultimo el método "run" propio de la clase "Runnable" tiene la mayoría de la lógica, en general se crea un archivo de acceso aleatorio (que nos permite escribir en cualquier parte del archivo local) y establecemos una conexion (indicando en el caso de una reanudación, desde donde iniciar la descarga, ver método "setRangeBytes", del archivo remoto). Por ultimo se lee el contenido completo o restante del archivo y se guarda localmente.

Como podes ver es extremadamente sencillo, en particular un punto de mejora para la clase es utilizar un ThreadPool y una actividad futura, para no solicitar un hilo de manera abrupta, les dejo el código y un ejemplito trivial probado :)



package cap4;

import javax.naming.spi.DirectoryManager;
import java.io.*;

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Observable;

/**
 * Ckase encargada de descargar un archivo, de forma paralela y con soporte de progreso y eventos.
 *
 * User: jsanca
 * Date: 4/17/13
 * Time: 11:27 PM
 * @author jsanca
 */
public class Download extends Observable implements Runnable, Serializable {


    // Tamano del bloque de descarga un kb
    private static final int MAX_BUFFER_SIZE = 1024;

    public enum Status {

        UNSTARTED,
        DOWNLOADING,
        PAUSED,
        COMPLETE,
        CANCELLED,
        ERROR
    } // Status.
    
    // URL a descargar.
    private URL url;

    // Tamano del archivo a descargar.
    private int fileSize;

    // Cantidad de bytes descargados.
    private int downloaded;

    // Estatus actual de la descarga.
    private Status status;
    
    private File baseDirectory;

    /**
     * Constructor.
     * @param url
     */
    public Download(final String url) throws MalformedURLException {

       this (new URL(url));
    } // Download.


    /**
     * Constructor.
     * @param url
     */
    public Download(final URL url) {

        this.url = url;
        this.fileSize = -1;
        this.downloaded = 0;
        this.baseDirectory = null;
        this.status = Status.UNSTARTED;
    } // Download.

    /**
     * Obtiene el porcentaje de progreso (de 1 a 100)
     * @return float
     */
    public float getProgress () {
        
        return (float) (this.downloaded / this.fileSize) * 100f;
    } // getProgress.

    /**
     * Pause la descarga actual.
     * Solo si esta se encuentra en descarga.
     */
    public void pause() {

        if (Status.DOWNLOADING == this.status) {

            this.status = Status.PAUSED;
            this.stateChanged();
        }
    } // pause.

    /**
     * Reanuda la descarga.
     * Solo si esta se encuentra pausada.
     */
    public void resume() {

        if (Status.PAUSED == this.status) {

            this.status = Status.DOWNLOADING;
            this.stateChanged();
            this.download();
        }
    } // resume.

    /**
     * Cancela la descarga, si y solo si, esta no esta descarga o en pausa
     */
    public void cancel() {

        if (Status.DOWNLOADING == this.status || Status.PAUSED == this.status) {

            this.status = Status.CANCELLED;
            this.stateChanged();
        }
    } // cancel.

    /**
     *  Se invoca cuando la descarga fracasa.
     */
    protected void error() {

        this.status = Status.ERROR;
        this.stateChanged();
    } // error.

    /**
     * Es invocado para disparar o reanudar la descarga de forma asincronica.
     */
    protected void download () {
        
        final Thread thread = new Thread(this);
        thread.start();
    } // download.

    /**
     * Invoque este metodo para iniciar la descarga.
     */
    public Download startDownload () {

        if (Status.UNSTARTED == this.status) {

            this.status = Status.DOWNLOADING;
            this.download();
        }

        return this;
    } // startDownload.

    /**
     * Get the file name (without the path) from the url.
     * @param aUrl URL
     * @return String
     */
    protected String getFileName (final URL aUrl) {

        String pathFileName = null;
        final String fileName = url.getFile();

        if (null != fileName) {

            pathFileName = fileName.substring(fileName.lastIndexOf('/') + 1);

            if (null != this.baseDirectory) {

                pathFileName = this.baseDirectory.getAbsolutePath() + "/" + pathFileName;
            }
        }

        if (null == fileName) {

            pathFileName = "unnamed" + System.currentTimeMillis();
        }

        return pathFileName;
    } // getFileName.

    public void run() {

        RandomAccessFile randomAccessFile = null;
        InputStream inputStream = null;
        HttpURLConnection httpURLConnection = null;
        int contentLength = 0;
        byte [] buffer;
        int readBytes;
        
        try {

            httpURLConnection =
                    (HttpURLConnection)this.url.openConnection();

            this.setRangeBytes(httpURLConnection, this.downloaded);

            httpURLConnection.connect();

            contentLength = this.checkErrors(httpURLConnection);

            // si el tamano no ha sido establecido, lo hago.
            if (-1 == this.fileSize) {

                this.fileSize = contentLength;
                this.stateChanged();
            }

            randomAccessFile =
                    new RandomAccessFile(this.getFileName(this.url), "rw");

            randomAccessFile.seek(this.downloaded);

            inputStream = httpURLConnection.getInputStream();

            while (Status.DOWNLOADING == this.status) {

                 buffer =
                         (this.fileSize - this.downloaded > MAX_BUFFER_SIZE)?
                                 new byte[MAX_BUFFER_SIZE]:
                                 new byte[this.fileSize - this.downloaded];

                 readBytes = inputStream.read(buffer);
                if (-1 == readBytes) {

                    break;
                }

                randomAccessFile.write(buffer, 0, readBytes);
                this.downloaded += readBytes;
                
                this.stateChanged();
            }

            // Marco la descarga como terminada.
            if (Status.DOWNLOADING == this.status) {
                
                this.status = Status.COMPLETE;
                this.stateChanged();
            }
        } catch (FileNotFoundException e) {

            error();
        } catch (IOException e) {

            error();
        } catch (DownloadErrorException e) {

            error();
        } finally {

            if (null != randomAccessFile) {

                try {

                    randomAccessFile.close();
                } catch (IOException e) {

                   // Quiet,
                }
            }

            if (null != inputStream) {

                try {

                    inputStream.close();
                } catch (IOException e) {

                    // Quiet,
                }
            }
        }
    } // run.

    private int checkErrors(final HttpURLConnection httpURLConnection) throws IOException {

        int contentLength;

        if (this.isAnErrorCode (httpURLConnection.getResponseCode())) {

            throw new DownloadErrorException("Response error = " + httpURLConnection.getResponseCode());
        }

        contentLength = httpURLConnection.getContentLength();

        if (contentLength < 1) {

            throw new DownloadErrorException("Content length invalid, length = " + contentLength);
        }
        return contentLength;
    } // checkErrors.

    /**
     * Determina si el codigo de respuesta esta en el rango de 200.
     * @param responseCode int
     * @return boolean
     */
    private boolean isAnErrorCode(final int responseCode) {

        return responseCode / 100 != 2;
    } // isAnErrorCode.

    /**
     * Especifica desde donde se iniciara la descarga del archivo (por ejemplo se puede iniciar desde la mitad) o reanudar una rescarga
     * @param connection HttpURLConnection
     * @param bytesSeek int
     */
    protected void setRangeBytes(final HttpURLConnection connection, final int bytesSeek) {

        connection.setRequestProperty("Range",
                new StringBuilder("bytes=").append(bytesSeek).append("-").toString());
    } // setRangeBytes.

    /**
     * Notifica a quien este viendo los cambios de estatos
     */
    protected void stateChanged() {

        this.setChanged();
        this.notifyObservers();
    } // stateChanged.


    /**
     * Asigna el directorio base para salvar el archivo.
     * En caso de ser nulo salva en el espacio de trabajo actual.
     * @param baseDirectory String
     */
    public void setBaseDirectory(final String baseDirectory) {

        this.setBaseDirectory(new File(baseDirectory));
    } // setBaseDirectory.

    /**
     * Asigna el directorio base para salvar el archivo.
     * En caso de ser nulo salva en el espacio de trabajo actual.
     * @param baseDirectory File
     */
    public void setBaseDirectory(final File baseDirectory) {

        if (null != baseDirectory && baseDirectory.exists()) {

            this.baseDirectory = baseDirectory;
        }
    } // setBaseDirectory.
} // E:O:F:Download.



El ejemplito Cambie "https://......jpg", por la direccion del archivo a descargar y /home/mydirectorio al archivo base al cual queremos descargar localmente.

public class Main {

    public static void main(String args[])
            throws java.io.IOException {

        Download download = new Download("https://......jpg");

        download.setBaseDirectory("/home/mydirectorio");

        download.startDownload();

    }
} // Main.

miércoles, abril 17, 2013

Analizador de expresiones algebraicas recursivo decendente


Como les mencione en un post previo, estoy leyendo el libro el arte de programar en Java, el primer ejercicio consiste en un analizador de expresiones algebraicas recursivo descendente, el mismo consiste en la posibilidad de tomar una cadena que contenga una expresión matemática, la misma puede contener valores en punto flotante, sumar, restar, dividir, multiplicar, sacar exponente (potencia), uso de paréntesis para priorizar una operación, etc.

A continuación clase a clase, con una pequeña explicación

Lo primero que definiremos es una suite de excepciones para reportar errores, no tiene mucha ciencia, hay una para la division entre cero, cuando no existe una expresión valida, error de sintaxis o cuando los paréntesis no se encuentran balanceados, veamos





package cap2;

/**
 * Exception para reportar que hay al intentar dividir entre cero
 *
 * User: jsanca
 * Date: 4/16/13
 * Time: 1:30 AM
 * @author jsanca
 */
public class DividedByZeroException extends RuntimeException {

    public DividedByZeroException() {
    }

    public DividedByZeroException(String message) {
        super(message);
    }

    public DividedByZeroException(String message, Throwable cause) {
        super(message, cause);
    }

    public DividedByZeroException(Throwable cause) {
        super(cause);
    }
}

//////

package cap2;

/**
 * Exception para reportar que no Hay expresion presente
 *
 * User: jsanca
 * Date: 4/16/13
 * Time: 1:30 AM
 * @author jsanca
 */
public class NonExpressionDefinedException extends RuntimeException {

    public NonExpressionDefinedException() {
    }

    public NonExpressionDefinedException(String message) {
        super(message);
    }

    public NonExpressionDefinedException(String message, Throwable cause) {
        super(message, cause);
    }

    public NonExpressionDefinedException(Throwable cause) {
        super(cause);
    }
}


////////

package cap2;

/**
 * Exception para reportar que hay un error de sintaxis
 *
 * User: jsanca
 * Date: 4/16/13
 * Time: 1:30 AM
 * @author jsanca
 */
public class SintaxErrorException extends RuntimeException {

    public SintaxErrorException() {
    }

    public SintaxErrorException(String message) {
        super(message);
    }

    public SintaxErrorException(String message, Throwable cause) {
        super(message, cause);
    }

    public SintaxErrorException(Throwable cause) {
        super(cause);
    }
}

package cap2;

/**
 * Exception para reportar que hay parentesis desbalanceados
 *
 * User: jsanca
 * Date: 4/16/13
 * Time: 1:30 AM
 * @author jsanca
 */
public class UnbalanceParenthesesException extends RuntimeException {

    public UnbalanceParenthesesException() {
    }

    public UnbalanceParenthesesException(String message) {
        super(message);
    }

    public UnbalanceParenthesesException(String message, Throwable cause) {
        super(message, cause);
    }

    public UnbalanceParenthesesException(Throwable cause) {
        super(cause);
    }
}

Seguidamente veremos el parser; el mismo contiene un constructor donde pasaras la formula a evaluar, seguidamente se normalizara (se eliminan los espacios).

Lo siguiente que podrás ver, es el TokenType. Este enumera los tipos de tokens, delimilador (un operador), variables (no soportadas en este ejemplo), números, fin de ecuación, etc.

Lo tercero son las variables de la clase, la expresión antes mencionada, el índice que se utilizara como veras mas adelante para recorrer la expresión índice a índice, el token (el numero, operador, etc, actual, en análisis) y el tipo de token como antes mencionamos.

Seguimos con la función "getResult" única función publica con la que el usuario puede interactuar, lo primer que hace la función es pedir el primer token, si este es fin de ecuación disparamos un excepción pues no debería ser (en este caso una expresión vacía), seguidamente por recursividad llamamos a evalExp2 (ya veras que lo que hace el algoritmo es encadenas descendentemente del operador de menor prioridad al de mayor, es decir vamos de sumas y restas, hasta multiplicación, exponentes, etc), esta evalExp2 debes conceptualizarla como la evaluacion de una suma si esta existe, pero antes buscara funciones de mayor prioridad; evalExp3.

EvalExp3 presenta un panorama similar, en este vemos como se evalúa las operaciones de multiplicar, division y modulo, sin no antes llamar antes a evalExp4.

La versión 4, evalúa la potencia, el exponente; así mismo este llamara al evalExp5 que evalua los algún signo de un operador como + o - (positivo o negativo).

Por ultimo evalExp6, evaluara paréntesis y valores atómicos, en nuestro caso solo números. En el caso de los paréntesis tomar en cuenta que cuando se encuentra un match, se vuelve a iniciar el proceso a través de un llamado recursivo a evalExp2, que evaluara la expresión dentro de los paréntesis.

No estoy seguro si entendiste la dinámica del algoritmo, pero este se basa en llamar primero a la operación de menor prioridad hasta ir directamente a la de mayor prioridad (paréntesis y números, el eslabón final en la cadena de la ecuación).

Lo ultimo que veras es el nexToken, este analizador resulta muy sencillo básicamente evalúa el carácter actual, en el caso de los delimitadores simplemente lo tome y suma uno mas para ir al siguiente índice en la llamada a nextToken consiguiente, en el caso de los números o variables (no soportadas en el ejemplo); se sacaran todos los digitos hasta encontrar otra cosa (un delimitador en este caso), esta función sera llamada a medida que se necesite analizar el siguiente token.

Pues ahora al código:

package cap2;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * Representa el parser para las expresiones
 * * User: jsanca
 * Date: 4/16/13
 * Time: 12:29 AM
 *
 * @author jsanca
 */
public class Parser {

    /**
     * Constructor.
     *
     * @param expresion String
     */
    public Parser(String expresion) {

        this.expresion = this.normalizeExpresion(expresion);
    }


    // define los tipos de token
    private enum TokenType {

        NONE, DELIMITER, VARIABLE, NUMBER, EOE
    }

    private String expresion = null;
    private int expresionIndex = 0;
    private String token = null;
    private TokenType tokenType = null;

    private Set delimiters = new HashSet(Arrays.asList(new Character[]{'+', '-', '/', '*', '%', '^', '=', '(', ')'}));

    private String normalizeExpresion(String expr) {

        return expr.replaceAll("\\s*", "");
    }

    /**
     * Gets the results
     *
     * @return double
     */
    public double getResult() {

        double result = 0;

        this.expresionIndex = 0;
        this.nextToken();

        if (this.tokenType == TokenType.EOE) {

            throw new NonExpressionDefinedException();
        }

        // evalua la expresion
        result = this.evalExp2();

        if (this.tokenType != TokenType.EOE) {

            throw new SintaxErrorException();
        }

        return result;
    } // getResult.

    /**
     * Suma o resta terminos
     *
     * @return double
     */
    private double evalExp2() {

        char operator;
        double result;
        double partialResult;

        // llamado decendente a la operacion de multiplicar
        result = this.evalExp3();

        while ( (this.tokenType != TokenType.EOE) &&
                ((operator = this.token.charAt(0)) == '+' || operator == '-')) {

            this.nextToken();
            partialResult = evalExp3();

            switch (operator) {

                case '-':

                    result = result - partialResult;
                    break;

                case '+':

                    result = result + partialResult;
                    break;

            }
        }

        return result;
    } // evalExp2.

    /**
     * Multiplica y divide
     *
     * @return double
     */
    private double evalExp3() {

        char operator;
        double result;
        double partialResult;

        // llamado decendente a la operacion de exponente
        result = this.evalExp4();


        while ( (this.tokenType != TokenType.EOE) &&
                ((operator = this.token.charAt(0)) == '*' || operator == '/' || operator == '%')) {

            this.nextToken();
            partialResult = evalExp4();

            switch (operator) {

                case '*':

                    result = result * partialResult;
                    break;

                case '/':

                    if (partialResult == 0.0) {

                        throw new DividedByZeroException();
                    }

                    result = result / partialResult;
                    break;

                case '%':

                    if (partialResult == 0.0) {

                        throw new DividedByZeroException();
                    }

                    result = result % partialResult;
                    break;

            }
        }

        return result;
    } // evalExp3,

    /**
     * Evalua el exponente
     *
     * @return double
     */
    private double evalExp4() {

        double result;
        double partialResult;

        // llamado decendente a la operacion de signo (unitario)
        result = this.evalExp5();

        if ("^".equals(this.token)) {

            this.nextToken();
            partialResult = this.evalExp4();

            if (partialResult == 0.0) { // x^0.0 = 1.0

                result = 1.0; // caso trivial
            } else {

                result =
                        Math.pow(result, partialResult);
            }
        }

        return result;
    } // evalExp4.

    /**
     * Evalua el signo de un valor + 0  -
     *
     * @return
     */
    private double evalExp5() {

        double result;
        String operator = "";

        if ((this.tokenType == TokenType.DELIMITER) &&
                "+".equals(this.token) || "-".equals(this.token)) {

            operator = this.token;
            this.nextToken();
        }

        // decendente parentesis
        result = this.evalExp6();

        if ("-".equals(operator)) {

            result = -result;
        }

        return result;
    } // evalExp5.

    /**
     * Evalua los parentesis.
     *
     * @return double
     */
    private double evalExp6() {

        double result;

        if ("(".equals(this.token)) {

            this.nextToken();
            result = this.evalExp2();

            if (!")".equals(this.token)) {

                throw new UnbalanceParenthesesException();
            }

            this.nextToken();

        } else {

            result = this.getAtomicValue();
        }

        return result;
    } // evalExp6.

    /**
     * Obtiene un valor numerico atomico
     *
     * @return double
     */
    private double getAtomicValue() {

        double result = 0.0;

        if (this.tokenType == TokenType.NUMBER) {

            result = Double.parseDouble(this.token);

            this.nextToken();
        } else {

            throw new SintaxErrorException();
        }

        return result;
    } // getAtomicValue.


    /**
     * Obtiene el siguiente token
     */
    protected void nextToken() {

        this.tokenType = TokenType.NONE;
        this.token = "";

        if (!isTheEndOfExpresion()) {

            // Si es un operador
            if (this.isDelimiter(this.expresion.charAt(this.expresionIndex))) {

                this.parseDelimiter();

            } else if (this.isVariable(this.expresion.charAt(this.expresionIndex))) { // si es una variable.

                this.parseVariable();

            } else if (this.isNumber(this.expresion.charAt(this.expresionIndex))) { // si es un numero.

                this.parseNumber();

            } else {

                this.tokenType = TokenType.EOE; // caracter desconocido.
            }
        } else {

            this.tokenType = TokenType.EOE;
        }

        System.out.println(MessageFormat.format("token {0} and type {1}", this.token, this.tokenType));

    } // nextToken.

    private void parseFactor() {

        while (!this.isTheEndOfExpresion() && !this.isDelimiter(this.expresion.charAt(this.expresionIndex))) {

            this.token += this.expresion.charAt(this.expresionIndex);
            this.expresionIndex++;
        }
    }

    protected void parseNumber() {

        this.parseFactor();

        this.tokenType = TokenType.NUMBER;
    }


    protected void parseVariable() {

        this.parseFactor();

        this.tokenType = TokenType.VARIABLE;
    }

    protected void parseDelimiter() {

        this.token +=
                this.expresion.charAt(this.expresionIndex);

        this.expresionIndex++;
        this.tokenType = TokenType.DELIMITER;
    }

    private boolean isNumber(final char c) {

        return Character.isDigit(c);
    } // isNumber,

    private boolean isDelimiter(final char c) {

        return this.delimiters.contains(c);
    } // isDelimiter.

    private boolean isVariable(final char c) {

        return Character.isLetter(c);
    } // isVariable.

    private boolean isTheEndOfExpresion() {

        return (this.expresionIndex >= this.expresion.length());
    } // isTheEndOfExpresion.


} // E:O:F:Parser.


lunes, abril 15, 2013

El arte de programar en Java

Tengo mas de una decada programando en Java, siento que me manejo de manera aceptable en el lenguaje, algunos frameworks, librerias y herramientas alrededor; sin embargo esa posicion de "comfort" creo que puede resultar perjudicial para el desarrollador, pues la mayoria de los retos que uno suele encontrar en el trabajo no pasan de ser cosas de gestion de datos, que implican seguridad, escalabilidad, entre otros aspectos muy importantes, pero a la poste algo triviales (ya se han hecho varias veces, algunas ocasiones hay retos interesantes, pero nada super emocionante).

En ese mundo "perfecto" creo que uno puede debilitar o perder ciertas habilidades cognitivas que solia tener en la Universidad, como un aceptable razonamiento logico matematico, entre otros; por tal razon me he dado a la tarea de volver algunos libros de logica, de la misma manera desempolvar algunos libros de programacion, uno interesante aunque algo viejo es "El arte de programar en Java", un libro que compre hace ya algun tiempo y consiste en una serie de ejercicios llevados en cada capitulo tales como un analizador de expresiones, interpretes, adminitrador de descargas, un cliente de correo electronico entre otros (osea retos que por lo regular no te pediran en el cotidiano trabajo).

Me gustaria ver si puedo ir haciendo aqui una bitacora con cada capitulo leido y publicar lo mas importante de cada uno, esperemos que no se quede en palabras ultimamente me cuesta trabajo ser consistente con un labor edenica :)


lunes, abril 08, 2013

Links acerca de usabilidad


Bueno esta haciendo un research acerca de usabilidad y decidi compartir algunos de los links mas interesantes:

Este esta muy cool y dice por que son buenos, gmail #1:

http://www.1stwebdesigner.com/design/well-designed-usable-sites/

Los mejores menus:
http://www.kronikmedia.co.uk/blog/website-navigation-menu-design/3580/

Otro top ten:
http://www.topsite.com/best/usability

los CMS con mas usabilidad
http://net.tutsplus.com/articles/web-roundups/top-10-most-usable-content-management-systems/

Las grandes companias que incorporan usabilidad en sus sistemas:
http://www.siteiq.net/7806/the-2013-usability-top-10-ibm-leads-sap-soars-and-apple-screws-up-the-rankings-2

+ Algo interesante:

top ten de sitios de Universidades
http://blog.thebrickfactory.com/2010/03/top-11-best-designed-university-websites/

Y estos son 10 videitos acerca de usabilidad:
http://www.usefulusability.com/10-must-see-usability-videos/

Enjoy!