martes, 11 de febrero de 2014

[MYSQL] Buscar varios ID no consecutivos utilizando una sola consulta



Hace un rato tenia un problema con respecto a como decir si un folio que quiero liberar ya fue liberado anteriormente, por la situación que una empresa libera folios según la región que se maneja, por lo que quería ver la manera de mandar un arreglo como parámetros a MYSQL para no tener que hacer una consulta por cada uno de los folios. La respuesta fue mas sencilla gracias al apoyo del licenciado. Lo único que se hizo fue poner todos los folios en una cadena separandolos por una coma, suponiendo que tengo un arreglo con los numeros de folio (OJO no necesariamente están consecutivos porque si no pues un between me ayudaría muy rápidamente). Por lo que supongamos que tenemos un arreglo llamado folios con la programación solo concatene de la siguiente manera (c#): 

string dato = "";
foreach(int i in folios) 
     {
         dato = dato + Convert.ToString(i);
         dato = dato + ",";
      }
dato = dato.Remove(dato.Length - 2);
Una vez tenido eso mande llamar el procedimiento tomando en cuenta que lo único que quiero saber es cuantos folios están repetidos. 

MySqlCommand SQLComando = new MySqlCommand("buscaFolios", SQLConexion);
SQLComando.CommandType = CommandType.StoredProcedure;
SQLComando.Parameters.AddWithValue("pparam", dato);                
MySqlDataReader reader = SQLComando.ExecuteReader();
reader.Read();                
int numero = Convert.ToInt32(reader["numero"]);
if (numero == 0)
  {
    MessageBox.Show("no folios repetidos");
  }
else
    MessageBox.Show("Existe ya " + numero + " de folios repetidos en la base de datos", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Almacenándolo en la variable numero si es 0 quiere decir que los folios no han sido usados, si no quiere decir que ya existen. Para el procedimiento almacenado puse lo siguiente : 

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `buscaFolios`(IN pparam TEXT)
BEGIN
   SELECT count(*) as numero  FROM mitablita WHERE pparam LIKE CONCAT('%', micampo, '%');
END

Y con esto ya tenemos un resultado como el siguiente: 



Espero les ayude

martes, 4 de febrero de 2014

[Codigo] Transformar de una expresion regular a un AF-e

Les comparto un código que hice en java.

Recibe como argumento al crear la clase una cadena como la siguiente como expresión: aba El resultado es una serie de string almacenados en una lista con el siguiente formato, la primer linea pone los terminales que componen el alfabeto en este caso e (vacio), a y b.

Las demas lineas se componen por:
 0-_&1&_
1-_&_&2
2-_&3&_
*3-_&_&_

 Por ejemplo en la primer linea, el primer numero significa el numero de nodo, si tiene un asterisco se toma como un nodo de aceptación. El guion separa el numero de nodos de las transiciones y van en el orden del alfabeto es decir el primero le corresponde a e(vacío) por lo que como en este caso no existen en el automata pues ponemos _, despues le sigue un & que significa que es el siguiente no terminal por lo tanto si es el primero viene un 1, porque quiere decir que con "a" se va al nodo 1, el ultimo & da vacío porque en el primer estado no avanza con b.

El proyecto esta basado en el algoritmo de thompson

El proyecto esta conformado por:

CobyException: Es una clase simbólica que yo programe para arrojar una serie de códigos como nuestra aplicación es solo un backend que trabajara por detrás no tiene interfaz grafica por lo que decidimos mandar los mensajes de validación a través de CobyException.

Codigo: 


package common;

/**
 *
 * @author cobymotion
 */
public class CobyException extends RuntimeException{
    /**
     * Codigos de error
     * Cod01: Es posible que la transicion se haya perdido revisar algoritmo
     * Cod02: Los operadores no pueden ir al principio y el operador + no puede ir al final
     * Cod03: En esta version no funcionan los parentesis
     * Cod 04: Los parentesis tienen un orden incorrecto
     * Cod05: Dos cerraduras de kleene juntas
     * Cod06: Dos operadores en un mal orden
     * @param codigo 
     */
    public CobyException(String codigo) {
        super(codigo);
    }
    
}


Points: Es un archivo plano de java que solo tiene como fundamental almacenar los puntos de inserción de las tablas, ya que en la primera versión no aceptaba paréntesis tuvimos que agregar dicha clase para almacenar puntos en los que se adaptarían las tablas.

Codigo: 


package common;

/**
 * Esta clase me permite almacenar los pares donde se enlazaran las tablas, 
 * solo me sirve como modelo
 * @author cobymotion
 */
public class Points {
    
    int init;
    int end; 

    public Points() {
    }

    public Points(int init) {
        this.init = init;
    }
    
    
}


TableTransition: Otra nueva clase que tenia como objetivo almacenar tablas de los contenidos de los paréntesis, es decir solo almacena resultados de lo que los paréntesis arrojan, en una expresión normal hay una tabla que por cada paréntesis lo sustituirá por letras Mayúsculas por lo que eso quiere decir que esa No terminal será sustituida por otra tabla

Codigo: 


package common;

import java.util.List;

/**
 * Clase modelo que solo permite almacenar las tablas que se van opteniendo del interno de los parentesis
 * @author cobymotion
 */
public class TableTransition {
    
    private List table; 
    private int num; 

    public List getTable() {
        return table;
    }

    public void setTable(List table) {
        this.table = table;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
    
    
    
    
}


ConvertToAFN: Siguiendo ayuda del algoritmo de Thompson que es una forma de convertir una expresión regular a un afd con e transición. 

Codigo: 


package common;

import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

/**
 *Clase que permite cambiar una expresion regular a un conjunto de lineas de texto
 * que representan una tabla de transicion de un automata-e
 * @author cobymotion
 */
public class ConvertToAFN {

    private String exp;

    /**
     * Constructor, permite solo instanciar la clase mandandole una expresion
     * Debe de cumplir con la forma correcta tomando en cuenta el cierre de
     * parentesis
     *
     * @param exp cadena con la expresion regular
     */
    public ConvertToAFN(String exp) {
        this.exp = exp;
    }
    
    
    /**
     * Obtiene el valor de la expresion que se esta evaluando
     * @return la expresion 
     */

    public String getExp() {
        return exp;
    }
    
    /**
     * Permite modificar el valor de la expresion que sera evaluada en el programa
     * @param exp Nueva expresion por la que sera cambiada
     */

    public void setExp(String exp) {
        this.exp = exp;
    }

    /**
     * Busca que la cadena no tenga ninguna mayuscula al dar de alta la cadena
     *
     * @return retorna verdadero si la encuentra
     */
    private boolean encuentraMayusculas() {
        boolean res = false;
        for (int i = 0; i < exp.length(); i++) {
            if (Character.isUpperCase(exp.charAt(i))) {
                res = true;
            }
        }
        return res;
    }

    /**
     * Metodo que regresa una serie de lineas de texto con el formato que tendra
     * logico el automata, esta clase solo saca tokens de los parentesis para
     * que sean convertidos, una vez que se convierten se concatena con lo ya
     * obtenido por la expresiòn
     *
     * @return lista, la primer linea esta compuesta por el alfabeto de la
     * expresión las demas lineas siguen el formato que la maestra sigue para
     * representacion de los algoritmos si regresa un null quiere decir que no
     * hay expresion a evaluar
     */
    public List toAFDe() {
        List AFDe = new ArrayList<>();
        List listTable = new ArrayList<>();
        if (encuentraMayusculas()) {
            throw new CobyException("Cod 08: Esta version de software no acepta mayusculas ya que tienen una función en el sistema");
        }
        if (faltaParentesis()) {
            throw new CobyException("Cod 07: Hay algun problema con los parenteris");
        } else if (!exp.contains("(")) {
            AFDe = toAFDInterno(exp);
        } else {
            List regInitial = toAFDInterno(getTables(exp, "", listTable, 0));
            //System.out.println(mergeADF(exp,"",listTable,0,0)); 
            TableTransition tableNew = new TableTransition();
            tableNew.setNum(listTable.size());
            tableNew.setTable(regInitial);
            listTable.add(tableNew);
            ///solo para probar que funciona 
            AFDe = mergeTables(listTable);
        /*    for (TableTransition tableTransition : listTable) {
                System.out.println("----------- " + tableTransition.getNum() + "---------");
                for (String cadena : tableTransition.getTable()) {
                    System.out.println(cadena);
                }
            }*/
        }
        return AFDe;
    }

    /**
     * Esta clase permite a cada bloque de parenteris convertirlo en una tabla
     * independiente
     *
     * @param exp La cadena con la expresion completa
     * @param nueva Es una cadena auxiliar que permite ir manejando los tokens
     * de la expresion
     * @param listTable Lista con las tablas que se fueron formando
     * @param i contador de caracteres
     * @return la expresion resultante despues de haber trabajado los parentesis
     */
    private String getTables(String exp, String nueva, List listTable, int i) {
        while (exp.length() > i && exp.charAt(i) != ')') {
            char car = exp.charAt(i);
            if (car == '(') {
                String nueva2 = getTables(exp, "", listTable, ++i);
                while (exp.length() > i && exp.charAt(i) != ')') {
                    i++;
                }
                nueva += String.valueOf((char) ('A' + listTable.size()));
                TableTransition tableNew = new TableTransition();
                tableNew.setNum(listTable.size());
                tableNew.setTable(toAFDInterno(nueva2));
                listTable.add(tableNew);
            } else {
                nueva += car;
                i++;
            }
        }
        return nueva;
    }
    
    /**
     * Junta las tablas en la ultima que fue almacenada en la lista
     * @param lista es un conjunto de tablas.
     * @return 
     */

    private List mergeTables(List lista) {
        List complete = lista.get(lista.size() - 1).getTable();
        /// 
        boolean mayus = false;
        do {
            mayus=false;
            String alphabet = complete.get(0);
            for (int i = 0; i < alphabet.length(); i++) {
                if (Character.isUpperCase(alphabet.charAt(i))) {
                //hay un cambio 
                    //obtener el registro que vamos a combianar 
                    mayus=true;
                    int nodo = (int) (alphabet.charAt(i) - 'A');
                    List tabla = lista.get(nodo).getTable(); //tabla que voy a unir a la otra
                    List nuevos = encuentraNodos(complete, i); //puntos donde unire
                    List finales = nodosFinales(tabla);
                    deleteColum(complete, i);
                    for (Points points : nuevos) {
                        int suma = complete.size() - 1;
                        linkTables(points, suma, complete, tabla,finales);
                    }
                }
            }
        } while (mayus);
        ///
        return complete;
    }
    
    /**
     * Enlaza las dos tablas para que puedan ser una sola, destino queda como resultdo de la union
     * @param point puntos donde se unira la tabla
     * @param suma valor de desface en los estados en la tabla nueva
     * @param destino lista con la tabla terminada
     * @param toJoin tabla que se va a unir
     * @param finales nodos que son de terminacion en la tabla que se unira
     */

    public void linkTables(Points point, int suma, List destino, List toJoin, Listfinales) {
        String alphabet = destino.get(0);
        String cambio = destino.get(point.init + 1);
        //mando el nodo inicial con e transicion a un nodo nuevo
        String partes[] = cambio.split("-");
        String tokens[] = partes[1].split("&");
        if (tokens[0].equals("_")) {
            tokens[0] = String.valueOf(suma);
        } else {
            tokens[0] += ",";
            tokens[0] += String.valueOf(suma);
        }
        cambio = partes[0];
        cambio += "-";
        boolean ban=false;
        for (int j = 0; j < tokens.length; j++) {
                cambio += tokens[j];
                cambio += "&";
                ban=true;
        }
        if(ban)
            cambio = cambio.substring(0, indexOfApersonFinal(cambio));
        destino.set(point.init+1,cambio);
        /// recorrer la tabla e irla uniendo 
        String alphabetExterno = toJoin.get(0);
        //merge alfabeto 
        alphabet = mergeAlphabets(alphabet,alphabetExterno,destino);
        destino.set(0, alphabet);
        //
        for(int i=1;i transiciones = new HashMap<>();
            for (int j = 0; j < tokens.length; j++) {
                String string = tokens[j];
                if(!string.equals("_"))
                {
                    //agrega nodo a la tabla destino 
                    String valores[] = string.split(",");
                    string = "";
                    for (String string1 : valores) {
                        int destinoNum = Integer.parseInt(string1) + suma;
                        string +=String.valueOf(destinoNum);
                        string +=",";
                    }
                    tokens[j] = string.substring(0, string.length()-1);
                    transiciones.put(alphabetExterno.charAt(j),tokens[j]);
                }
            }
            //crea una cadena para agregar a destino 
            String cadena = ""; 
            cadena += (destino.size()-1); 
            cadena += "-";
            for(int j=0;j destino, int pos, Points point){
        String cadena = destino.get(pos);
        String partes[] = cadena.split("-");
        String tokens[] = partes[1].split("&");
        if (tokens[0].equals("_")) {
            tokens[0] = String.valueOf(point.end);
        } else {
            tokens[0] += ",";
            tokens[0] += String.valueOf(point.end);
        }
        String cambio = partes[0];
        cambio += "-";
        boolean ban=false;
        for (int j = 0; j < tokens.length; j++) {
                cambio += tokens[j];
                cambio += "&";
                ban=true;
        }
        if(ban)
            cambio = cambio.substring(0, indexOfApersonFinal(cambio));
        destino.set(pos,cambio);
       
    }
    
    /**
     * Sirve para poder agregar una columna en caso que haya elementos que no esten en el alfabeto
     * @param destino La serie de cadenas ya con el formato
     */
    private void agregarcolumna(List destino){
        for(int i=1;i nodosFinales(List complete){
        List finales = new ArrayList<>();
        for(int i=1;i complete, int colum) {
        //empezar a settear todas las cadenas 
        String alphabet = complete.get(0);
        alphabet = alphabet.replace(String.valueOf(alphabet.charAt(colum)), "");
        complete.set(0, alphabet);
        for (int i = 1; i < complete.size(); i++) {
            String cadena = complete.get(i);
            String partes[] = cadena.split("-");
            String tokens[] = partes[1].split("&");
            cadena = partes[0].toString();
            cadena += "-";
            for (int j = 0; j < tokens.length; j++) {
                if (j != colum) {
                    cadena += tokens[j];
                    cadena += "&";
                }
            }
            cadena = cadena.substring(0, indexOfApersonFinal(cadena));
            complete.set(i, cadena);
        }
    }
    
    /**
     * Obtiene la posicion donde esta el ultimo aperson para eliminar la columna
     * @param cadena la cadena de la entrada 
     * @return retorna la posicion 
     */

    private int indexOfApersonFinal(String cadena) {
        for (int i = cadena.length() - 1; i >= 0; i--) {
            if (cadena.charAt(i) == '&') {
                return i;
            }
        }
        return 0;
    }

    /**
     * Encuentra todos los nodos que tengan una relacion con otra tabla
     *
     * @param cambios Es lista que tiene el automata como va quedando
     * @param nodo numero de columna donde encontro una relacion con otra tabla
     * @return returna la lista ya modificada
     */
    private List encuentraNodos(List cambios, int nodo) {
        List nuevos = new ArrayList<>();
        Iterator ite = cambios.iterator();
        //nodo++;
        ite.next();
        while (ite.hasNext()) {
            String tokens[] = ite.next().toString().split("&");
            if (!tokens[nodo].equals("_")) {
                Points punto = new Points();
                punto.end = Integer.parseInt(tokens[nodo]);
                int num = obtenerNumero(tokens[0]);
                punto.init = num;
                nuevos.add(punto);
            }
        }
        return nuevos;
    }

    /**
     * Este metodo se utiliza para extraer el numero de nodo donde se unira la
     * tabla
     *
     * @param cad cadena que se buscara digitos para convertirlos en numero, no
     * considera que puden estar separados
     * @return returna un entero con el numero que se obtuvo
     */
    private int obtenerNumero(String cad) {
        String subcadena = "";
        for (int i = 0; i < cad.length(); i++) {
            if (Character.isDigit(cad.charAt(i))) {
                subcadena += cad.charAt(i);
            }
        }
        int numero = 0;
        try {
            numero = Integer.parseInt(subcadena);
        } catch (NumberFormatException e) {
            numero = -1;
        }
        return numero;
    }

    /**
     * El metodo que permite convertir pequeñas expresiones en el formato de
     * AFDe
     *
     * @param exp se lleva la expresion que esta dentro de un parentesis y la
     * expresion completa sin parentesis
     * @return
     * @throws CobyException
     */
    private List toAFDInterno(String exp) throws CobyException {
        //algunas validaciones 
        if (exp.charAt(0) == '*' || exp.charAt(0) == '+' || exp.charAt(exp.length() - 1) == '+') {
            throw new CobyException("Cod02: Los operadores no pueden ir al principio y el operador + no puede ir al final");
        } else if (exp.contains("(") || exp.contains(")")) {
            throw new CobyException("Cod03: Se escapo un parentesis en un token");
        } else if (exp.contains("**")) {
            throw new CobyException("Cod05: Dos cerraduras de kleene juntas");
        } else if (exp.contains("+*")) {
            throw new CobyException("Cod06: Dos operadores en un mal orden");
        }

        //usa ya por definicion la expresion regular que viene especificada en la ca
        //primero declaramos las variables que se necesitaran
        String[][] table = new String[100][100]; //tabla de transciciones 
        //contadores
        int col, row, contnodos, trans, inicial;
        int ban = 0;
        col = row = 0;
        //agregamos al alfabeto la e 
        table[0][1] = "e";
        //agregamos el nodo inicial 
        table[1][0] = "0";
        //actualizamos la posicion donde empezaran 
        row = 2;
        trans = 1;
        inicial = 1;
        contnodos = 0;
        //recorremos la expresión de caracter en caracter 
        for (int i = 0; i < exp.length(); i++) {
            //capturamos el caracter a evaluar 
            char car = exp.charAt(i);
            //hacemos comparaciones de los posibles operadores +,*,(,)
            if (car == '+') {
                trans = inicial;
                table[row - 1][0] = "*" + table[row - 1][0];
                ban = 0;
            } else if (car == '*') {
                //cuando es un solo bloque el que sigue entonces regresar la expresion 
                if (ban == 1) {
                    String auxExp = exp.substring(0, i);
                    // auxExp = auxExp;
                    auxExp += "e";
                    auxExp += String.valueOf(exp.charAt(i - 1));
                    auxExp += "*";
                    exp = auxExp + exp.substring(i + 1);
                    table[1][0] = "*" + table[1][0];
                    i--;

                } else {
                    // como la transicion que se maneja es de izquierda a derecha se regresa el control al nodo anterior
                    row--;
                    trans = row;
                    int pos = backNode(table[row - 1], table[0], contnodos--, exp.charAt(i - 1)); //aqui tengo un Errorvuelvo despues
                    if (pos == -1) {
                        throw new CobyException("Cod01: Es posible que la transicion se haya perdido revisar algoritmo");
                    }
                    table[row - 1][pos] = String.valueOf(contnodos);
                    String auxExp = exp.substring(0, i);
                    // auxExp = auxExp;
                    auxExp += "e";
                    exp = auxExp + exp.substring(i + 1);
                    i--;
                    trans--;
                }
            } else { // si no es un operador entonces consideramos que es un elemento del alfabeto
                int posCol = updateAlfabeto(table[0], car);
                contnodos++;
                if (table[trans][posCol] != null) {
                    table[trans][posCol] += ",";
                    table[trans][posCol] += String.valueOf(contnodos);
                } else {
                    table[trans][posCol] = String.valueOf(contnodos);
                }
                table[row][0] = String.valueOf(contnodos);
                trans = row;
                row++;
                ban++;
            }
        }
        //actualiza el ultimo nodo para que se haga de aceptacion 
        table[row - 1][0] = "*" + table[row - 1][0];
        /*  for (int i = 0; i < 10; i++) {
         System.out.println(Arrays.toString(table[i]));
         }*/
        List formatoDiaz = toConvertFormatDiaz(table, row);
        return formatoDiaz;
    }

    /**
     * Esta funcion se encarga de agarrar una matriz en array convertirlo a un formato 
     * visto en clases por la Maestra Miriam Diaz
     * @param table matriz con las transiciones
     * @param row numero de lineas que tiene la matriz
     * @return Retorna una lista con cadenas que representan la tabla segun el formato
     */
    public List toConvertFormatDiaz(String[][] table, int row) {
        List formato = new ArrayList<>();
        int i = 1;
        String alphabet = "";
        while (table[0][i] != null) {
            alphabet += table[0][i];
            i++;
        }
        formato.add(alphabet);

        String linea = "";
        for (int j = 1; j < row; j++) {
            linea = "";
            for (int k = 0; k < i; k++) {
                if (table[j][k] != null) {
                    linea += table[j][k];
                } else {
                    linea += "_";
                }
                if (k == 0) {
                    linea += "-";
                } else {
                    linea += "&";
                }

            }
            formato.add(linea.substring(0, linea.length() - 1));
        }
        return formato;
    }

    /**
     * Permite verificar que los parentesis tengan la misma cantidad entre los
     * que abren y cierran Puede ser que esta funcion no salga porque no tenemos
     * un orden adecuado de los parentesis
     *
     * @return un verdadero si faltan parametros
     */
    private boolean faltaParentesis() {
        Stack pila = new Stack<>();
        for (int i = 0; i < exp.length(); i++) {
            if (exp.charAt(i) == '(') {
                pila.push(1);
            } else if (exp.charAt(i) == ')') {
                try {
                    pila.pop();
                } catch (EmptyStackException e) {
                    throw new CobyException("Cod 04: Los parentesis tienen un orden incorrecto");
                }
            }
        }
        if (pila.empty()) {
            return false;
        } else {
            return true;
        }
    }

    /**
     *
     * @param rowData la linea que tiene el valor que se va a modificar
     * @param rowAlphabet manda la primer linea donde esta el alfabeto
     * @param contNodos el numero de nodo que cambiara por si mismo para formar
     * ciclo
     * @param car el caracter del estado que se hizo una transcicion anterior
     * para buscar la posición
     * @return posicion donde esta el parametro que vamos a cambiar, regresa
     * menos -1 si no funciona
     */
    private int backNode(String[] rowData, String[] rowAlphabet, int node, char car) {
        int pos = -1;
        try {
            pos = updateAlfabeto(rowAlphabet, car);
        } catch (Exception e) {
            pos = -1;
        }
        return pos;
    }

    /**
     * Este metodo se encarga verificar si ya existe un elemento en el alfabeto
     * en la primera linea de la tabla si no existe entonoces lo agrega
     *
     * @param rowAlfabeth lleva solo la primera linea del arreglo
     * @param car el caracter que se agrega en el alfabeto
     * @return Regresa la posicion donde se encuentra el caracter en el alfabeto
     */
    private int updateAlfabeto(String rowAlphabet[], Character car) {
        int pos = 1;

        while (rowAlphabet[pos] != null) {
            if (rowAlphabet[pos].equals(car.toString())) {
                return pos;
            }
            pos++;
        }
        rowAlphabet[pos] = car.toString();
        return pos;
    }

    
    /**
     * Solo me extrae las transiciones
     * @param cambio
     * @return retorna un arreglo con las transiciones
     */

    private String[] internos(String cambio) {
        String partes[] = cambio.split("-");
        String tokens[] = partes[1].split("&");
        return tokens;
    }
    
    /**
     * Combina mediante cadenas los alfabetos para que son repetidos 
     * @param oAlphabet Alfabeto de origen 
     * @param dAlphabet alfabeto que se unira
     * @param destino lista de la tabla  
     * @return cadena ya con el alfabeto combinado
     */

    private String mergeAlphabets(String oAlphabet, String dAlphabet, List destino) {
          for(int i=0;i resultado = oConvert.toAFDe();
        for (String string : resultado) {
         System.out.println(string);
         }
    }
    
}



Espero les sirva 

sábado, 4 de enero de 2014

Cronometro con Zepto publicación en Firefox marketplace


Viendo un curso me encontré este ejemplo con un framework llamado zepto que en pocas palabras lo que hace es facilitar el acceso a los componentes DOM de una manera mas sencilla usando JavaScript (por lo menos en el ejemplo es lo que vamos a hacer). 
Para bajar la librería lo hacemos directamente del siguiente sitio: http://zeptojs.com/ 
El framework viene muy completo aunque no tuve mucha oportunidad de probarlo un poco mas. 
En esta tarea se hizo un pequeño cronometro muy sencillo pero que puede ser muy útil y sencilla de hacer. 
El cronometro esta creado en base a una pagina HTML 5 teniendo un aspecto muy sencillo pero funcional, solo lo componen una carpeta con iconos, la librería de zepto, la pagina html, un htaccess y un webapp para su publicación. 

Primero lo que vamos a hacer es el archivo index.html que prácticamente es el cronometro que se va a necesitar. 

Para esto esta compuesto por el siguiente código:

<!DOCTYPE html>
<html>
<head> 
 <title> Cronómetro </title>
 <meta charset="UTF-8">
 <script type="text/javascript" src="zepto.min.js"> </script>
 <script type="text/javascript">
  $(function(){
   localStorage.c = (localStorage.c || "0.0");
   var t, cl=$("#crono");
   function incr() { localStorage.c = +localStorage.c+0.01;}
   function mostrar(){cl.html((+localStorage.c).toFixed(2));}
   function arrancar(){t=setInterval(function(){incr();mostrar()},10);}
   function parar(){clearInterval(t); t=undefined;}
   function cambiar(){if(!t) arrancar(); else parar();}
   $("#cambiar").on('click',cambiar);
   $("#inicializar").on('click', function(){localStorage.c="0.0"; mostrar();});
   mostrar(); 
  });
 </script> 
 </head>
 <body>
    <center>
    <h2>Cronómetro</h2>
    <h3><span id="crono">0.0</span> Segundos </h3>
    <button type="button" id="cambiar"> Arrancar/Parar</button>
    <button type="button" id="inicializar">Inicializar</button>
     </center>
 </body>
</html>


Para el código anterior hay que tomar en cuenta los script que se tienen al principio que nos permiten arrancar, incrementar, mostrar, inicializar nuestro contador. También tomemos en cuenta la variable localstorage.c donde c es la variable y el objeto localstorage nos sirve para que lo almacene de forma local permitiendo que se almacene y pueda mantener el valor.

Lo segundo que vamos a necesitar es manejar diferentes tamaños de los iconos por lo que los ponemos en una carpeta que pueda ser alcanzada por la pagina no tiene uso para la aplicación pero tiene uso para cuando se haga la publicación de la aplicación. 

Una vez terminado creamos un archivo manifest.webapp que contendrá lo siguiente: 


{
 "name":"Cobycronometro",
 "description":"Cronometro con almacenamiento local",
 "launch_path":"/mydir/",
 "icons":{
 "128":"/mydir/img/icons/time128.png",
 "32":"/mydir/img/icons/time32.png",
 "64":"/mydir/img/icons/time64.png",
 "48":"/mydir/img/icons/time48.png"
 },
 "type":"web",
 "developer":{
 "name":"Luis Cobian",
 "url":"http://luiscobian.blogspot.mx/"
 },
 "default_locale":"es",
 "version":"1.0"
}

Ahí tomen en cuenta que los iconos al hacer un directorio no hay problema pero cuando subimos a un servidor como en mi caso se maneja el direccionamiento desde el nombre del dominio, por ejemplo si dice /img/icons/image.png y la aplicacion esta guardada en un dominio.com en la carpeta aplicacion las referencias al los iconos debe de ser "/aplicacion/img/icons/image.png"

Para continuar cree un archivo .htaccess con la linea siguiente para que pueda validar correctamente la tienda de firefox 

AddType application/x-web-app-manifest+json .webapp

Terminando solo abrimos una cuenta en: https://marketplace.firefox.com/


Ahí tendrás que dar la ruta completa donde esta el manifest, ahi tendras que tener ya tener todos tus archivos en un servidor web para que puedan ser encontrados, una vez terminando te pedirá datos de tu aplicación, datos de los servicios de pagos (en este caso como es gratuita no tuve que pagar), políticas y por ultimo te dará la oportunidad de administrar los datos mientras te validan la aplicación que en este momento el cronometro esta validándose, en cuando sepa el resultado lo hago saber.



martes, 26 de noviembre de 2013

Uso de la etiqueta @Font-face en CSS para importar tipografía a nuestra pagina


Uno de los problemas que tenemos al tratar de desarrollar una pagina mas los que vamos empezando es que la tipografía que yo tengo en mi computadora muchas veces va acorde a lo que tengo programando, pero recordemos que estas tras un mundo de posibles clientes a tu, por lo que puede ser que tu cliente no tenga el estilo de fuente que tu ves que en tu sitio es el adecuado, por lo que en la parte de CSS 3 tenemos la siguiente etiqueta font-face para importar la tipografía directamente el servidor o directamente desde un servicio publico.

Buena para eso su uso viene especificado directamente en la referencia CSS3 de la siguiente manera:

@font-face
{
font-family: myFirstFont;
src: url('Sansation_Light.ttf'),
     url('Sansation_Light.eot'); /* IE9 */
}

Por ejemplo en la imagen que estoy utilizando manejo un tipo de letra FiraSansOT-RegularItalic para el texto y para encabezado chango. La primera de ellas la traigo directamente de la carpeta de mi servidor y la otra la vinculo al servicio de google fonts

Primero voy a crear mi pagina
<!DOCTYPE html>
<html>
<head>  
   <title> Probando Css Externo</title>
   <link href="theme.css" rel="stylesheet" type="text/css"></link>
   <link href="http://fonts.googleapis.com/css?family=Chango" rel="stylesheet" type="text/css"></link>
</head>
<body>
   <h1>
Pagina de prueba </h1>
<p>
Esta es una pagina para probar etiquetas con
formato en css en un archivo externo  para mejor
acomodo</p>
</body>
</html>


Notemos la linea

 <link href='http://fonts.googleapis.com/css?family=Chango' rel='stylesheet' type='text/css'>

Esta linea hace referencia a que se manejara un servicio de google fonts para poder hacer la llamada, con eso ya tengo activado chango

Por ultima creamos nuestra hoja de estilo css



@font-face {
 font-family: Propia;
 src: url(FiraSansOT-RegularItalic.otf) format("opentype");
}

p{
 font-family: Propia;
}

h1{
 font-family: 'Chango', cursive;
}

Una interfaz sencilla utilizando GTK 3.0, Bluez y C

En el post anterior estuvimos viendo como crear una interfaz de una forma sencilla de la siguiente forma nuestra intención es que podamos controlar un mini-robot y podamos activar los motores para su movimiento.


Lo primero que vamos a necesitar es un chasis para mini robot proposito general, arduino, un puente H, pilas, bluetooth shield para arduino y algunos cables para las conexiones. (No abarcaremos las conexiones puesto que el objetivo del post es la programación)

Estamos utilizando en este ejemplo una versión de Linux en este caso Mint para poder hacer toda la programación, para eso necesitamos las librerías estándar de programación y en este caso bluez que ya viene prácticamente ya viene instalado solo necesitamos las librerías que usaremos.

Pues vamos a instalarlo lo primero que debemos hacer es poner el siguiente comando:

$ sudo apt-get install libbluetooth-dev

Una vez que tenemos instalado las librerias, vamos a trabajarlo directamente en el codigo que estamos utilizando para la interfaz por lo que para este ejemplo el arduino tiene programado que cuando reciba una "a", prenda los motores para que avance el carro, cuando recibe una "r" hacia atrás, "i" a la izquierda y "d" a la derecha.

Empezaremos por declarar el socket para podernos comunicarnos por bluetooth

    struct sockaddr_rc addr = { 0 };
    int status;
    char dest[18] = "00:13:03:19:00:50";
    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    addr.rc_family = AF_BLUETOOTH;
    addr.rc_channel = (uint8_t) 1;
    str2ba( dest, &addr.rc_bdaddr );
    status = connect(s, (struct sockaddr *)&addr, sizeof(addr));

Donde en el arreglo de "dest" tenemos la dirección tarjeta por ultimo con status(si es  0 se conecto) revisamos que realmente se haya podido dar la conexión.

Una vez que todo haya salido correcto, añadiremos los cuatro metodos para que puedan mover el carro:

//methods
static void go(GtkWidget *widget, gpointer data){
    int status = write(s,"a",6);
    if( status < 0 ) perror("uppps error");
    //printf("avanzo");
}

static void back(GtkWidget *widget, gpointer data){
    int status = write(s,"r",6);
    if( status < 0 ) perror("uppps error");
}

static void left(GtkWidget *widget, gpointer data){
    int status = write(s,"i",6);
    if( status < 0 ) perror("uppps error");
}


static void right(GtkWidget *widget, gpointer data){
    int status = write(s,"d",6);
    if( status < 0 ) perror("uppps error");  
}


Por ultimo verificamos que cuando salgamos de la ventana se cierre la conexión 

static gboolean delete_window(GtkWidget *widget, GdkEvent *event, gpointer data){
     close(s);
     gtk_main_quit();
     return FALSE;
}


Aquí muestro el código completo no hay separación por lo que basta seguirlo de la siguiente manera 

///Bluetooth Library 
#include 
#include 
#include 
#include 

#include 
//variables
int s; 

//methods
static void go(GtkWidget *widget, gpointer data){
    int status = write(s,"a",6);
    if( status < 0 ) perror("uppps error");
    //printf("avanzo");
}

static void back(GtkWidget *widget, gpointer data){
    int status = write(s,"r",6);
    if( status < 0 ) perror("uppps error");   
}

static void left(GtkWidget *widget, gpointer data){
    int status = write(s,"i",6);
    if( status < 0 ) perror("uppps error");
}


static void right(GtkWidget *widget, gpointer data){
    int status = write(s,"d",6);
    if( status < 0 ) perror("uppps error");    
}

static gboolean delete_window(GtkWidget *widget, GdkEvent *event, gpointer data){
     close(s);
     gtk_main_quit();
     return FALSE;
}

static void close2(GtkWidget *widget, gpointer data) {
    close(s);
}

int main (int argc, char *argv[]) {

    //manager bluetooth
    struct sockaddr_rc addr = { 0 };
    int status;
    char dest[18] = "00:13:03:19:00:50";
    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    addr.rc_family = AF_BLUETOOTH;
    addr.rc_channel = (uint8_t) 1;
    str2ba( dest, &addr.rc_bdaddr );
    status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
    //A program that has a window and four buttons to control the mini-robot    

    //Declaration of variables or components 
    GtkWidget *window; 
    GtkWidget *buttonUp;
    GtkWidget *buttonDown;
    GtkWidget *buttonLeft;
    GtkWidget *buttonRight;
    GtkWidget *grid;
    GtkWidget *label;
    GtkWidget *cerrar; 
    //initialization 
    gtk_init (&argc, &argv);
    /// create a new Window 
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    // Set title for window
    gtk_window_set_title (GTK_WINDOW (window), "Control automatico");
    // Set window resize 
    gtk_window_set_default_size(GTK_WINDOW(window), 385, 395);
    // Method for destroying the window    
        g_signal_connect(window,"delete_event",G_CALLBACK(delete_window),NULL);
    if(status==0){ 
    //create grid
        grid = gtk_grid_new();
        gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
        gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE);
    //add container 
        gtk_container_add(GTK_CONTAINER(window),grid);    
    //Create buttons and append in to Grid
        buttonUp = gtk_button_new_with_label("Avanzar");
        g_signal_connect(buttonUp,"clicked",G_CALLBACK(go),NULL);
        gtk_grid_attach(GTK_GRID(grid),buttonUp,2,0,1,1);        
        buttonDown = gtk_button_new_with_label("Atras");
        g_signal_connect(buttonDown,"clicked",G_CALLBACK(back),NULL);
        gtk_grid_attach(GTK_GRID(grid),buttonDown,2,2,1,1);
        buttonLeft = gtk_button_new_with_label("Izquierda");
        g_signal_connect(buttonLeft,"clicked",G_CALLBACK(left),NULL);
        gtk_grid_attach(GTK_GRID(grid),buttonLeft,1,1,1,1);
        buttonRight = gtk_button_new_with_label("Derecha");
        cerrar = gtk_button_new_with_label("Read");
        gtk_grid_attach(GTK_GRID(grid),cerrar,0,0,1,3);
        g_signal_connect(cerrar,"clicked",G_CALLBACK(close2),NULL);
        g_signal_connect(buttonRight,"clicked",G_CALLBACK(right),NULL);
        gtk_grid_attach(GTK_GRID(grid),buttonRight,5,1,1,1);    
    //show the widgets
    }else {
        label = gtk_button_new_with_label("No se encontro Device");
        g_signal_connect(label,"clicked",G_CALLBACK(delete_window),NULL);
        gtk_container_add(GTK_CONTAINER(window),label);
    }
    gtk_widget_show_all (window);
    gtk_main ();

}


Lo guardamos con extensión .c (en mi caso carro.c) y lo compilamos de la siguiente manera

$ gcc carro.c -o carro `pkg-config --cflags --libs gtk+-3.0` -lbluetooth

Una vez que tenemos ya nuestro programa lo ejecutamos y probamos

$ ./carro

Funcionamiento:

miércoles, 20 de noviembre de 2013

Una interfaz sencilla utilizando GTK 3.0


Vamos a realizar un simple interfaz con cuatro botones a puro código utilizando GTK, que posteriormente nos servirá para controlar un pequeño mini-robot por medio de bluetooth. 


El código esta programado en C y utilizando las librerías de GTK 3.0 compilado y ejecutado en un entorno de Linux Mint por lo que comente el codigo  de lo que fui entendiendo: 

  //Autor : José Luis Cobian
// @cobymotion
// Work with GTK 
//noviembre 2013

#include 
//method for window destroy 
static gboolean delete_window(GtkWidget *widget, GdkEvent *event, gpointer data){
     gtk_main_quit();
     return FALSE;
}

int main (int argc, char *argv[]) {

    //A program that has a window and four buttons to control the mini-robot
    //Declaration of variables or components 
    GtkWidget *window; 
    GtkWidget *buttonUp;
    GtkWidget *buttonDown;
    GtkWidget *buttonLeft;
    GtkWidget *buttonRight;
    GtkWidget *grid;
    //initialization 
    gtk_init (&argc, &argv);
    /// create a new Window 
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    // Set title for window
    gtk_window_set_title (GTK_WINDOW (window), "Control automatico");
    // Set window resize 
    gtk_window_set_default_size(GTK_WINDOW(window), 385, 395);
    //create grid
    grid = gtk_grid_new();
    //Expand the window across the grid
    gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
    gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE);
    //add container 
    gtk_container_add(GTK_CONTAINER(window),grid);
    // Method for destroying the window    
    g_signal_connect(window,"delete_event",G_CALLBACK(delete_window),NULL);
    //Create buttons and append in to Grid
    buttonUp = gtk_button_new_with_label("Avanzar");
    gtk_grid_attach(GTK_GRID(grid),buttonUp,1,0,1,1);
    buttonDown = gtk_button_new_with_label("Atras");
    gtk_grid_attach(GTK_GRID(grid),buttonDown,1,4,1,1);
    buttonLeft = gtk_button_new_with_label("Izquierda");
    gtk_grid_attach(GTK_GRID(grid),buttonLeft,0,2,1,1);
    buttonRight = gtk_button_new_with_label("Derecha");
    gtk_grid_attach(GTK_GRID(grid),buttonRight,4,2,1,1);    
    //show the widgets
    
     gtk_widget_show_all (window);
     gtk_main ();

}


Para compilarlo utilizamos: 

gcc carro.c -o carro `pkg-config --cflags --libs gtk+-3.0`


Espero les sirva 




viernes, 1 de noviembre de 2013

[Mint] Error: Your Firefox profile cannot be loaded. It may be missing or inaccessible


Uno de los mejores navegadores que hay, si no que el mejor es Firefox, pero en las semanas pasadas los que tenemos equipos con ubuntu o en su caso tenemos equipos con Mint hemos tenido un pequeño problema, en la actualizacion de firefox 25. 

Si después de actualizar tienes el problema siguiente: 

Your Firefox profile cannot be loaded. It may be missing or inaccessible

La forma de solucionarlo es sencilla el problema principal es que en el cache de la carpeta de firefox no se ha podido acceder al perfil, por lo que solo hay que dar los permisos, para esto primero entramos a la carpeta: 

cd ~/.mozilla/firefox/

Estando ahí borraremos el de profiles.ini

Despues nos cambiaremos de carpeta a la de cache por lo que entramos con el comando 

cd ~/.cache

Estando ahí solo daremos permisos al usuario para que pueda acceder y posteriormente pueda crear un perfil nuevo. 

sudo chown -R coby:coby ./mozilla

Teniendo en cuenta que mi usuario se llama Coby, únicamente ingresamos el password y listo, puedes abrir tu firefox espero les haya servido. 

Saludos!