miércoles, 5 de noviembre de 2014

Sushi Dragon

Hola a todos!
Os quiero presentar Sushi Dragon! El juego para Android que he creado.
Durante un año estuve desarrollando mi propio engine 2D sobre el SDK de android basado en OpenGL ES 1.0.
Decidí hacerlo completamente de cero, incluso implementé el sistema detector de gestos sobre las funciones básicas de la SDK de android.
Como primer proyecto mostrando las funcionalidades de mi engine Iwok2D, presento Sushi Dragon. 
Un juego para que los más pequeños se diviertan cuidando, disfrazando y jugando con un pequeño dragón azul comedor de sushi!
Este es el enlace para descargarlo: Sushi Dragon en Play Store!


Espero que os guste, y que os animeis a probarlo!
Para aquellos que tengáis dudas sobre el proceso de desarrollo, diseño, distribución, inclusión de publicidad, etc. No dudeis en preguntar!
Un saludo a todos!

Aquí os dejo el enlace a mi portal de desarrollo de juegos:


martes, 23 de septiembre de 2014

CSS: Bordes redondeados CSS

Buenas a todos!
Para tener divs con los bordes redondeados compatibles con todos los navegadores la clase css contendrá los siguientes atributos:

-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;

Div con los bordes redondeados!

10px lógicamente hace referencia al radio.

Un saludete!

CSS: Fondo transparente con CSS

Buenas a todos!

Esta es una solución cross browser, para tener fondos transparentes en CSS.
El color lo indicamos con los valores rgb, el último parámetro de rgba indica el porcentaje de opacidad.

div.bg_opacity{
    background: rgb(0, 0, 0) transparent;
    background: rgba(0, 0, 0, 0.6);
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";
}

Un saludete!

miércoles, 17 de septiembre de 2014

Apuntes de C++: Sobrecarga de funciones, constructores de copias y argumentos implícitos

Buenas a todos!
El siguiente post, continua con los apuntes sobre C++, esta vez resumo un poco el tema de la sobrecarga de funciones contructoras, los constructores de copias y los argumentos implícitos. Finalizo con algo curioso, obtener punteros que apunten a funciones sobrecargadas.

Las funciones constructoras de clase se pueden sobrecargar, pero las funciones destructoras no.


class Persona{
    int x;
public:
    Persona(){ x=0; }       //Constructor sin inicializador
    Persona(int n){ x=n; }  //Constructor con inicializador
};

En el código anterior tenemos la función constructora sobrecargada.
Sin la versión de constructor sin inicializador, no podría inicializarse un array dinámico, y se generaría un error en tiempo de compilación.

Persona *persona;
persona = new Persona[20];

Con el constructor sin inicializador el array dinámico persona, contiene 20 objetos de tipo persona, con x = 0.

Cuando se pasa un objeto a una función o esta lo devuelve pueden presentarse dificultades, ya que automáticamente se generan copias del objeto.

Al pasar un objeto a una función se realiza una copia bit a bit de ese objeto. Hay cosas que no deseamos que sean idénticas en la copia, como por ejemplo si el objeto original apunta a la memoria asignada por un puntero, la copia apuntará a la misma dirección de memoria, y la copia podría alterar la memoria original.

Cuando una función devuelve un objeto, normalmente el compilador generará un objeto temporal que mantiene una copia del valor devuelto por la función. Esta acción es automática y no controlable.
Este objeto desaparece al devolver su valor y al desaparecer llama a su función destructora.

Para evitar estos problemas se puede definir un "constructor de copias", un tipo especial de función constructora sobrecargada.

Situaciones en las que se aplica un constructor de copias

Los constructores de copias sólo se aplican a situaciones de inicialización, no de asignación.
Hay tres situaciones de inicialización típicas:
- Se emplea un objeto para inicializar otro en una declaración.
myclass x = y;
- Se pasa un objeto como parámetro a una función.
funcionX(y);
- Se crea un objeto temporal al devolver un objeto por una función.
y = funcionX();

class Persona{
    int x;
public:
    Persona(){ x=0; }       //Constructor sin inicializador
    Persona(int n){ x=n; }  //Constructor con inicializador
    Persona(const Persona &obj){…}//Constructor de copias
};

Argumentos implícitos

Usar argumentos implícitos es una forma abreviada de sobrecarga de funciones.
void f(int a = 0, int b = 0);
La función anterior emplea como argumentos implícitos los parámetros a y b.
Este tipo de declaración permite llamar a la función f de las siguientes formas:

f();    //a=0, b=0
f(5);   //a=5, b=0
f(5,2); //a=5, b=2

No hay forma de dar valor por defecto a 'a' y especificar 'b'.
Los argumentos implícitos deben ser constantes o variables globales.

Búsqueda de la dirección de una función sobrecargada

Igual que en C es posible asignar la dirección de una función a un puntero y acceder a la misma a través del puntero:

p = zap;  //donde tenemos zap();

Para obtener la dirección de una función sobrecargada, es el modo de declarar el puntero el que determina la dirección de la función sobrecargada.

void space(int count);
void space(int count, char ch);
main(){
    void (*fp1)(int);   //puntero a una función void con un parámetro int
    void (*fp2)(int)(char);
    
    fp1 = space;    //void space(int count);
    fp2 = space;    //void space(int count, char ch);
    
    fp1(22);
    fp2(30, 'x');
}


En el siguiente post, continuaré con la sobrecarga de operadores.
Un saludo a todos!


domingo, 7 de septiembre de 2014

Apuntes de C++ : Arrays y punteros

Continuando con los resúmenes de mis apuntes del libro "C++ guia de autoenseñanza" de Herbert Schildt, en este post trataré los Arrays, los punteros y las referencias.

Cómo crear un array

int lista[20];
Esta línea crea un array de 20 elementos de tipo entero.

Para crear un array de objetos de una clase concreta, se emplea la misma sintaxis:

class Nave_espacial{
    int r;
    int g;
    int b;
public:
    Nave_espacial(int r, int g, int b);
    void setColor(int r, int g, int b);
};

void Nave_espacial::setColor(int r, int g, int b){...}

main(){
    Nave_espacial naves[20];
    naves[0].setColor(255, 0 , 0);  
}

Creamos un array para 20 objetos de tipo Nave_espacial y modificamos el color de la primera nave de la lista.

Nave_espacial naves[2] = { Nave_espacial(1,2,3) ,  Nave_espacial(4,5,6) };

Este tipo de inicialización del array, permite llamar a las funciones constructoras de cada uno de los objetos del array pasándoles los parámetros que sean necesarios.

Punteros a objetos


class Muestra{
     int id, valor;
public:
     Muestra(int _id, int _valor){ id = _id; valor = _valor; }
     int getId(){ return id; }
     int getValor(){ return valor; }
};

main(){
     int i;
     Muestra muestras[4] = {
          Muestra(0, 20),
          Muestra(1, 23),
          Muestra(2, 21),
          Muestra(3, 23)
     };
     Muestra *m;
     m = muestras;

     for(i=0; i<4; i++){
          cout << m->getValor() << " , ";
          m++; 
     }
}

Creamos un puntero m para apuntar a objetos de la clase Muestra, y cogemos la dirección del array.
Cuando se incrementa el puntero, este apunta al próximo objeto del array.
Para emplear las funciones miembro de los objetos se emplea el operador ->.

Uso de new y delete

En C la asignación de memoria dinámica se realizaba mediante malloc() y la memoria asignada se liberaba utilizando free(). Estas funciones estándar siguen siendo válidas en C++.
C++ proporciona un método más seguro para asignar memoria y liberar memoria, new y delete.

Muestra *m;
m = new Muestra(2, 40);
delete m;

Creamos un puntero para objetos de una clase en concreto.
new nos devuelve un puntero a la memoria asignada dinámicamente, que es lo suficientemente grande como para contener el objeto de la clase.
delete devuelve la memoria cuando ya no se necesita.

Si no hay memoria disponible para asignar, new devuelve un puntero nulo.
Solamente debe llamarse delete con punteros obtenidos previamente mediante new. En caso contrario, se bloquea el sistema de asignación, interrumpiéndose el programa.

new asigna automáticamente la memoria necesaria para albergar un objeto del tipo especificado, así que no es necesario emplear sizeof para calcular el número de bytes requeridos.
Tanto new como delete pueden sobrecargarse permitiendo que el programador cree a su medida su propio sistema de asignación de memoria.

m = new Muestra[10];

El puntero m apuntará a la primera posición de un array de 10 objetos de clase Muestra.
Para eliminar un array asignado dinámicamente, se emplea la siguiente instrucción:

delete []m;

Así el compilador llama a la función destructora para cada elemento del array, y m no se libera en múltiples ocasiones, se libera sólo una vez.

Referencias: pasar parámetros por referencia a una función

K = 10;
void sumarK(int *n);

void sumarK(int *n){
    *n = *n + K;
}

main(){
    int i = 5;
    sumarK(&i);
    cout << "Valor de i = " << i;
}

Por defecto, C++ pasa los parámetros por valor, lo que significa que realiza una copia de los mismos y que si alteramos su valor dentro de las funciones, la variable original que se ha pasado a la función no se ve afectada.
En este ejemplo la función sumarK(int *n) recibe como parámetro un puntero a un entero, lo que significa que cuando realizamos la llamada debemos pasar como parámetro la dirección de la variable entera, para coger dicha dirección o referencia, empleamos el operador &i.

Al hacer esto la función f trabaja directamente con la variable original, ya que altera el valor contenido en la dirección apuntada por el puntero.

En C la definición de paso por referencia sólo puede hacerse de la anterior forma, pero en C++ puede automatizarse para simplificarse el paso por referencia:


K = 10;
void sumarK(int &n);

void sumarK(int &n){
    n = n + K;
}

main(){
    int i = 5;
    sumarK(i);
    cout << "Valor de i = " << i;
}

Simplemente es necesario añadir el operador de dirección al declarar la función, &n.
Hecho esto el compilador ya sabe que realmente cuando se haga la llamada sumarK(i) lo que está pasando como parámetro es la dirección de la variable i.
Y del mismo modo tampoco hace falta indicar dentro de la implementación de la función, que n es un puntero.

Importante: no se pueden modificar las direcciones a las que apunta una referencia.

Pasar parámetros por referencia es la mejor forma de evitar los problemas asociados con la copia de argumentos, que al llamar a sus funciones destructoras pueden perjudicar partes del programa.

Una referencia no es un puntero. Cuando se pasa un objeto por referencia su operador de acceso a atributos y funciones miembro, es el punto "." y no la flecha "->".

Devolución de referencias

Una función puede devolver una referencia. Y podemos asignar directamente valores a la dirección de dicha referencia, es decir, una función puede estar en el lado izquierdo de una asignación.
El siguiente ejemplo es una locura, para los que nunca han trabajado con punteros o están muy acostumbrados a lenguajes como Java.
Vamos a crear una clase Array, para almacenar arrays de enteros.
Y en la función main vamos a hacer que las posiciones 2 y 3 del array contengan los valores 4 y 30:


class Array(){
     int size;
     int *set;
public:
     Array(int _size);
     int &put(int i);
     int get(int i);
};

Array::Array(int _size){
     set = new int[_size];
     size = _size;
}

int &Array::put(int i){
     if(!(i<0 || i>=size)) return set[i]; //devuelve una referencia a set[i]
}

int Array::get(int i){
     if(!(i<0 || i>=size)) return set[i]; //devuelve el entero contenido en set[i]
}

main(){
     Array a(20);
     a.put(2) = 4;
     a.put(3) = 30;
}     

Para que una función devuelva una referencia debemos poner el operador & delante del nombre de función.
Una vez hemos indicado esto automáticamente el compilador sabe que debe devolver la dirección de set[i] y no el valor que contiene.

Una referencia no puede ser referenciada.
No pueden crearse arrays de referencias.
Las referencias son similares a los punteros, pero no son punteros.

Hasta aquí la segunda parte de los apuntes de C++.
Espero que estos resúmenes os sirvan de "referencia" y os sean de utilidad!
Un saludo a todos!!

sábado, 6 de septiembre de 2014

Apuntes de C++

El siguiente post, no es un tutorial en sí. Son fragmentos a modo de síntesis de mis apuntes escritos durante la lectura del libro "C++ guia de autoenseñanza" de Herbert Schildt. Un libro lleno de ejemplos y perfecto para empezar de cero o volver a recordar C++.


Sobrecarga de funciones

En C++ varias funciones pueden tener el mismo nombre mientras el tipo o el número de sus argumentos sea distinto. Cuando ocurre esto, se dice que son funciones sobrecargadas.


Funciones constructoras en C++
Las funciones contructoras de una clase en C++ tienen el mismo nombre que la clase y no incluyen ningún tipo de retorno.

class Sprite{
public:
int x;
int y;
Sprite();
Sprite(int x, int y);
~Sprite();
};

Sprite::Sprite(){
x = 0;
y = 0;
}

Sprite::Sprite(int _x, int _y){
x = _x;
y = _y;
}

Sprite::~Sprite(){
cout << "Destruyendo el sprite \n";
}

int main(int argc, char *argv[]){
Sprite sp;
cout << "Position x " << sp.x;
}

Es importante ver que a diferencia de otros lenguajes como java o javascript, en C++ una sentencia de declaración de variable es una sentencia de acción, que desencadena que sea llamado el constructor sin parámetros.
También C++ permite que se ejecute una función cuando el objeto va a ser destruido, son las llamadas funciones destructoras, y tienen el mismo nombre que la clase pero vienen precedidas por el símbolo ~. Las funciones destructoras no pueden tener parámetros.
Los objetos locales se destruyen al salir de su ámbito y los objetos globales se destruyen al finalizar el programa.

No se puede obtener la dirección ni de las funciones constructoras ni de las destructoras.

Herencia en C++
En este ejemplo tenemos una clase B que hereda de una clase A:

class A{
int x;
public:
void setX(int _x);
int getX();
};

class B : public A{
int y;
public:
void setY(int _y);
int getY();
};

La declaración de la clase B indica al compilador que B heredará de la clase A, y tendrá públicos los mismos elementos que se hayan definido como públicos en la clase A, pero que todos los elementos de la clase base A permanecerán privados para B, de forma que no serán accesibles directamente.
El hecho de que una clase derivada no tenga acceso directo a las propiedades privadas de su clase base es para mantener la encapsulación.

La sintaxis parar realizar herencia es la siguiente:
class nombre_clase_derivada : tipo_acceso nombre_clase_base{...};

El tipo de acceso puede ser public, private o protected.

Punteros a objeto
A diferencia de lenguajes como Java en el que siempre que pasamos un objeto como parámetro de una función, este es pasado por referencia. Lo que significa que realmente estamos pasando la dirección de ese objeto y que todas las modificaciones que hagamos dentro de la función afectarán al objeto en sí. En C++ si queremos modificar un objeto dentro de una función, debemos especificar la dirección que hace referencia a dicho objeto, esto es lo que llamamos un puntero a un objeto.
Un puntero a objeto es una variable que contiene la dirección de memoria donde está contenido el objeto.

class Televisor{
int pulgadas;
public:
Televisor(int _pulgadas);
int getPulgadas();
};
Televisor::Televisor(int _pulgadas){
pulgadas = _pulgadas;                      
}
int Televisor::getPulgadas(){
return pulgadas;
}

int main(int argc, char *argv[]){
    Televisor tele(32);
    Televisor *t;
    t = &tele;
    cout << "Pulgadas " << t->getPulgadas();
    return 0;
}

"Televisor *t" define un puntero para apuntar a objetos de la clase Televisor.
"t = &tele" asigna la dirección del objeto tele al puntero t.
"t->getPulgadas()" ejecuta la función miembro del objeto tele.

Clases, estructuras y uniones

Las clases y las estructuras tienen prácticamente las mismas capacidades.
En C++ las estructuras pueden incluir funciones miembro, incluyendo funciones constructoras y destructoras.
La única diferencia es que por defecto los miembros de una clase son privados y los miembros de una estructura son públicos.

struct nombre_estructura{
...miembros públicos...
private:
...miembros privados...
}lista_objetos;

Tanto struct como class crean nuevos tipos de clase.
Al poseer las mismas capacidades, es una cuestión de preferencias decidir emplear struct o class. Pero lo más común es emplear struct para objetos que no tienen funciones miembro.

Las uniones en C++ también definen tipos de clase y también pueden contener funciones miembro.
Las uniones son como estructuras, por defecto tienen todos los miembros públicos hasta que se usa el especificador private. Su característica principal es que todos los miembros comparten la misma posición de memoria (como en C).
La capacidad de las uniones para enlazar código y datos permite crear tipos de clases en los que todos los datos usan una posición compartida. Esto no puede hacerse usando una clase.
Las uniones no pueden heredar de otra clase ni ser clases base. Tampoco pueden tener ningún miembro static, ni contener objetos que tengan un constructor o destructor. Pero las uniones sí pueden tener constructor y destructor.

Funciones insertadas

C++ permite definir funciones que realmente no son llamadas sinó que son insertadas en el código en el momento de la llamada. Como no tienen asociado el mecanismo de llamada y vuelta de la función, pueden ejecutarse más rápidamente que las funciones normales.
La desventaja es que si son demasiado largas y se las llama muy a menudo, el programa aumentará su longitud.
Una función inline se debe definir antes de ser llamada.

inline tipo_retorno nombre_funcion(parámetros){...}

inline es una solicitud no una obligación para el compilador. Todo depende de las restricciones del compilador en concreto, si no la hace insertada, la compilará como una función normal.

Inserción automática
En la declaración de una función miembro se puede incluir su definición si es suficientemente corta. Esto provoca que la función se convierta automáticamente en una función insertada, si es posible. La palabra clave inline, en este caso no es necesaria.

Asignación de objetos
Cuando asignamos un objeto a otro, se hace una copia a nivel de bits de todos los miembros. Los contenidos de los datos del objeto asignado se copian en los miembros equivalentes.
La asignación hace que los dos objetos sean idénticos, pero están realmente separados.

a = b;

Copia los valores de los datos miembros de b en el objeto a. Si posteriormente modificamos a o b, son completamente independientes.

Paso de objetos a funciones

Por omisión todos los objetos se pasan por valor a una función. Esto significa que se hace una copia idéntica del objeto y es la copia la que es usada por la función. Los cambios que se hagan dentro de la función en el objeto no afectan al objeto pasado como parámetro.
Cuando se hace una copia de un objeto para usarla en una llamada a función, no se llama a la función constructora. Sin embargo, cuando la función finaliza y la copia se destruye, se llama a la función destructora. Ya que los objetos pueden haber asignado memoria que debe ser liberada. Esto puede ser fuente de problemas. Ya que, si un objeto pasado como parámetro asigna memoria dinámica y al acabar la función se llama a su función destructora y esa memoria se libera, el objeto original quedará dañado y sin uso efectivo.
Hay que asegurarse de que las funciones destructoras de las copias de objetos pasados por valor, no provoquen efectos laterales que inutilicen los objetos originales.

Para evitar esto es mejor pasar la dirección de los objetos y no los objetos en sí. Al pasar una dirección, no se crea un nuevo objeto y no se llama a ningún destructor cuando se sale de la función.

Objetos devueltos por funciones

Cuando un objeto es devuelto por una función, se crea automáticamente un objeto temporal que guarda el valor devuelto. Después de devolver el valor, este objeto se destruye. La destrucción de este objeto temporal puede causar efectos laterales inesperados en algunas situaciones.
Si el objeto devuelto por una función tiene una función destructora que libera dinámicamente memoria asignada, esa memoria puede quedar liberada incluso aunque el objeto al que se asigna el valor devuelto lo siga utilizando.
Lo principal es entender que cuando un objeto es devuelto desde una función, el objeto temporal usado para hacer efectivo el retorno habrá llamado a su función destructora.

Introducción a las funciones amigas

Una función amiga no es un miembro de una clase pero tiene acceso a sus elementos privados.
Las funciones amigas principalmente son útiles para la sobrecarga de operadores y la creación de funciones de E/S o para que una función tenga acceso a los miembros privados de dos o más clases diferentes.

class A{
    int n;
public:
    friend int nombre_función ( A obj );
};

int nombre_función ( A obj ){
    obj.n++;
    return obj.n;
}

Las funciones amigas no son funciones miembro y no se puede acceder a ellas mediante un nombre de objeto. La llamada a la función se realiza como una llamada normal.
Las funciones amigas no se heredan. Si una clase base tiene una función amiga, esta función no es amiga de las clases derivadas de esta clase base.
Una función amiga puede ser amiga de más de una clase.

Referencias anticipadas
C++ permite hacer referencias anticipadas para poder emplear nombres de clases que todavía no han sido declarados. Para hacer esto, debemos advertir al compilador antes de realizar la referencia, que el nombre en concreto que vamos a usar pertenecerá a una clase. Lo hacemos de la siguiente forma:

class nombre_clase_A;

Función miembro de una clase y amiga de otra clase


class Cliente;

class Vendedor : public Persona{
    int id_vendedor;
    float salario;
public:
    int numero_ventas(Cliente c);
};

class Cliente : public Persona{
    int id_cliente;
public:
    friend int Vendedor::numero_ventas(Cliente c);
};

int Vendedor::numero_ventas(Cliente c){...}




Hasta aquí la primera parte de los apuntes sobre C++!
Un saludo a todos!!

viernes, 11 de abril de 2014

Ubuntu: crear alias para comandos y mantener los cambios en ~/.bash

Buenas a todos!
Normalmente cuando empleamos mucho el shell de ubuntu, tenemos que repetir muchas veces los mismos comandos, esto puede acabar ralentizando nuestro trabajo.
Por ejemplo, supongamos que estamos  editando archivos de configuración de un servidor nginx y constantemente tenemos que estar escribiendo:
nano /etc/nginx/sites-available/default

Sería mucho más cómodo poder poner en cualquier momento, nginxconf y que se ejecutara esa misma instrucción para editar el archivo. Podemos conseguir esto empleando la instrucción alias, que asigna a un nombre de variable una cadena que define una instrucción:

root@ubuntu:/# alias nginxconf='nano /etc/nginx/sites-available/default'

Ahora si escribís nginxconf, en la consola directamente se ejecutará la instrucción que habéis indicado.
Pero si reiniciais el equipo, el alias desaparecerá.

Modificar el archivo ~/.bash para mantener los alias

Para que los alias que necesiteis sean permanentes y no tengáis que crearlos cada vez que reiniciais el equipo, debéis editar el archivo ~/.bash.
Abrir el archivo bashrc:
sudo nano ~/.bashrc

Al final del archivo debéis escribir la instrucción que crea el alias:
alias nginxconf='nano /etc/nginx/sites-available/default'

Guardáis los cambios (control+X y Yes), y cuando el equipo reinicie, los cambios se habrán aplicado.

Aplicar los cambios del archivo ~/.bash sin reiniciar el equipo

Para no tener que reiniciar, y que los alias que hayáis introducido ya estén disponibles, podéis ejecutar la siguiente instrucción:

sudo source ~/.bashrc

Y con esto ya está todo!
Un saludo!

jueves, 10 de abril de 2014

MongoDB: borrar una base de datos en MongoDB

Buenas a todos!
Para borrar una base de datos en MongoDB desde la línea de comandos, debemos seleccionar la base de datos que queremos borrar y emplear la instrucción dropDatabase():
Por ejemplo vamos a borrar la base de datos mydb:

root@ubuntu:/# mongo

> show dbs
db0     0.203125GB
db_world        0.203125GB
mydb    0.203125GB

show dbs, nos muestra las bases de datos activas de MongoDB.

> use mydb
switched to db mydb

Seleccionamos como base de datos actual mydb.

> db.dropDatabase()
{ "dropped" : "mydb", "ok" : 1 }

Borramos la base de datos mydb y ahora mostramos de nuevo las bases de datos:

> show dbs
db0     0.203125GB
db_world        0.203125GB

Como podéis ver ya no se muestra mydb en el listado de bases de datos.

Y eso es todo! Un saludo a todos!

MongoDB: crear una base de datos en MongoDB

Buenas a todos!

Crear una base de datos en MongoDB es tan simple como abrir el cliente del servidor en el shell, y usar la instrucción use y el nombre de la base de datos.

root@ubuntu:/# mongo
> use db_nueva
switched to db db_nueva

Esta instrucción comprueba si ya existe la base de datos, y entonces asigna su referencia a la variable db, para que podamos consultar, y realizar otras operaciones sobre esta base de datos en concreto. En caso de que no exista, crea la base de datos.

Si cerramos el cliente en este punto, la base de datos desaparecerá ya que no contiene ninguna collection, que son los equivalentes a las tablas de SQL.
De hecho, si ejecutamos el comando que muestra las bases de datos "show dbs", no mostrará nuestra base de datos.

Basta con que creemos una collection, en este caso products.
> db.createCollection("products")
{ "ok" : 1 }

Una vez hecho esto la base de datos ya se ha creado y podemos verla en la lista de bases de datos:
> show dbs
db_nueva     0.203125GB

Para un acercamiento mayor, podéis visitar el post Hello World MongoDB, introducción a MongoDB!

Un saludete!

Hello World MongoDB, introducción a MongoDB

Buenas a todos!

Voy a hacer una pequeña introducción o Hello world en MongoDB!

A diferencia de las bases de datos relacionales típicas, como Oracle o MySQL, que emplean el lenguaje de declarativo SQL, MongoDB emplea para generar las consultas, inserciones, actualizaciones y eliminaciones, JavaScript!

Además los resultados obtenidos por las consultas están en formato JSON, lo que es perfecto cuando trabajamos con aplicaciones web.

Equivalencias entre conceptos de SQL y conceptos de MongoDB 

En MongoDB no tenemos tablas, trabajamos con collections.

Y lo que equivaldría a una fila o row de una tabla en SQL, en MongoDB es un document o BSON document. Los BSON documents son los que almacenan los objetos json en formato binario.

Los objetos json contienen campos o fields, no columnas como las tablas SQL.

De todas formas ambos sistemas de base de datos emplean las primary keys, para definir los campos que identifican de forma única una fila o un document (objeto json).

Mientras que en SQL hay que especificar la creación de todas las columnas de una tabla, MongoDB de forma automática crea un campo o field llamado _id que contiene la primary key, es un comportamiento por defecto muy útil.

Hello world MongoDB

Muy bien! Vamos a crear una pequeña base de datos a modo de Hello world para MongoDB.

La base de datos se llamará 'db_world' y contendrá paises del mundo, un listado con los idiomas que se hablan y las capitales.

Una vez instalado MongoDB, vamos a ejecutar en el shell de linux, la instrucción "mongo".

Crear la base de datos
> use db_world Si no existe, la crea y asigna a la variable db una referencia a las instancias de db_world.
Si ya existe, asigna a la variable db una referencia a las instancias de db_world.

Crear una collection e insertar un objeto
> db.world.insert({country:"Spain", capital:"Madrid", language:["es","ca","eu","gl"]}) Al realizar el insert se crea automáticamente la collection world, y directamente se inserta el objeto json que contiene los datos del país.

Consultar los datos de una collection
> db.world.find() Genera la salida:
{ "_id" : ObjectId("534665c91895da39bc16ff56"), "country" : "Spain", "capital" : "Madrid", "language" : [ "es", "ca", "eu", "gl" ] }

Como podéis ver automáticamente ha añadido el campo primary key _id, y la salida es el objeto json.

Ahora vamos a añadir otro país:
> db.world.insert({country:"Switzerland", capital:"Berna", language:["fr","de","it"]})

Si volvemos a realizar el find sobre la collection world, generará la siguiente salida:
> db.world.find() Genera la salida:
{ "_id" : ObjectId("534665c91895da39bc16ff56"), "country" : "Spain", "capital" : "Madrid", "language" : [ "es", "ca", "eu", "gl" ] }
{ "_id" : ObjectId("5346665762bac1c0ff258610"), "country" : "Switzerland", "capital" : "Berna", "language" : [ "fr", "de", "it" ] }

find() también nos permite consultar los objetos que contienen un valor específico.
Por ejemplo, supongamos que queremos ver el país cuya capital es Berna:
> db.world.find({capital:"Berna"})
Respuesta:
{ "_id" : ObjectId("5346665762bac1c0ff258610"), "country" : "Switzerland", "capital" : "Berna", "language" : [ "fr", "de", "it" ] }

O algo más complejo, supongamos que queremos ver los países donde se habla francés:
> db.world.find({language:{$in:["fr"]}})
 Respuesta:
{ "_id" : ObjectId("5346665762bac1c0ff258610"), "country" : "Switzerland", "capital" : "Berna", "language" : [ "fr", "de", "it" ] }


Cómo podéis ver, en ningún momento he tenido que declarar la estructura de los objetos que debe contener la collection world, eso es debido a que al igual que los objetos de javascript, las collections de MongoDB no obligan a cumplir una estructura determinada, de hecho su estructura puede variar dinámicamente, añadiendo o quitando campos, mediante el uso de update().

Hasta aquí mi introducción a MongoDB!
Espero que haya sido fácil de entender y que os anime a utilizarlo!

Un saludo a todos!!

martes, 1 de abril de 2014

Android: activar la vibración del móvil

Buenas a todos!!

Para que nuestras aplicaciones puedan hacer uso de la vibración del móvil es necesario que incluyamos en el AndroidManifest.xml el permiso VIBRATE:

<uses-permission android:name="android.permission.VIBRATE"/>

Una vez hecho esto, desde cualquier punto de nuestro código podemos crear una instancia de la clase Vibrator:

Vibrator v = (vibrator) getSystemService(Context.VIBRATOR_SERVICE);

Y para hacer que vibre, hacemos una llamada al método vibrate indicando los milisegundos que queremos que el móvil se mantenga vibrando:

v.vibrate(500);

Con esto hacemos que el móvil vibre 500 milisegundos o lo que es lo mismo, medio segundo.

Y eso es todo! Un saludo!

MySQL: instalar MySQL en Ubuntu Server

Buenas a todos!
Para instalar MySQL en Ubuntu desde la consola debemos ejecutar la siguiente instrucción:

sudo apt-get install mysql-server

Una vez hecho esto, el servidor de base de datos MySQL ya está en funcionamiento, ahora para que sea capaz de aceptar conexiones externas, debemos modificar el archivo de configuración que se encuentra en /etc/mysql/my.cnf

nano /etc/mysql/my.cnf

Y en el apartado bind-address, sustituir la ip que encontremos, por la ip de nuestro servidor.
bind-address = 120.200.10.130
La ip de nuestro servidor la podemos ver gracias al comando ifconfig, en el apartado inet.

Una vez hecho esto reiniciamos el servidor MySQL con la siguiente instrucción:

sudo /etc/init.d/mysql restart

Y eso es todo! El servidor MySQL ya está instalado, ahora lo más conveniente es que sean añadidos usuarios para poder realizar conexiones a la base de datos.
Para saber como añadir usuarios, podéis consultar el siguiente post:
http://iwokloco-appweb.blogspot.com.es/2014/04/mysql-crear-un-usuario-con-todos-los.html

Un saludo a todos!

Ubuntu: crear el password para la cuenta root

Buenas a todos!
Es muy importante que tengamos activo el superusuario root, para poder realizar todos los cambios que queramos en Ubuntu, instalar software, crear usuarios, asignar privilegios, etc.

sudo passwd root

Una vez indiquemos el password ya podemos trabajar como root, solamente tenemos que poner la instrucción "su", nos pedirá la contraseña introducida, y ya tenemos activo el superusuario para realizar todos los cambios e instalaciones que necesitemos!

usuario@ubuntu:/$ su
Password:
root@ubuntu:/#


Un saludo!

Ubuntu: configurar cliente ssh para conectarnos con Putty

Buenas a todos!
Para conectarnos y administrar de forma remota y segura a nuestros servidores Ubuntu empleamos el protocolo SSH, este protocolo encripta la información que transmitimos durante la comunicación.
Para poder emplear el protocolo ssh, es necesario que el servidor ubuntu, tenga instalado un servidor ssh.
En la consola de ubuntu instalamos openssh-server:
> sudo apt-get install openssh-server

Una vez instalado, el servicio ssh estará activado y ya podremos conectarnos remotamente.
Para ver la ip de nuestro servidor podemos emplear el comando.
> ifconfig

El valor que nos interesa es la ip inet.

Para conectarnos desde otro ordenador, en este caso vamos a emplear un cliente ssh  para windows llamado PuTTy.  Una vez lo tengáis descargado, sólamente tenéis que ejecutarlo (no requiere instalación) y indicar la ip de vuestro servidor remoto.

El username y password para administrar el equipo, son los de cualquier usuario que tengáis en vuestro sistema Ubuntu.

Un saludo a todos!

Ubuntu: configurar el teclado español por la consola

Buenas a todos!
En muchas ocasiones, cuando trabajamos sobretodo con ubuntu server instalado en máquinas virtuales VMWare, nos podemos encontrar con que las teclas de nuestro teclado no se corresponden con los carácteres que se muestran. Esto suele deberse a que por defecto tiene configurado el mapeo de teclados en inglés, donde no hay ñ.
Para poder usar nuestro teclado español sin problemas, sólo tenemos que ejecutar la siguiente instrucción:

sudo loadkeys es

Y con esta simple instrucción se soluciona el problema!
Un saludo a todos!

MySQL: crear un usuario con todos los privilegios en MySQL

Buenas a todos!
Crear un usuario administrador con todos los privilegios en MySQL desde la consola puede seros muy útil. Con este usuario podréis conectaros desde el MySQL Workbench, o directamente para trabajar a través de la consola, o simplemente para conectaros desde los servidores web.

mysql> use mysql;
mysql> GRANT ALL PRIVILEGES ON *.* TO admin@"%" IDENTIFIED BY 'password' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;


Hecho esto, ya podemos conectarnos empleando el usuario "admin" y con el password "password".

Espero que os sea útil! Un saludete!

Ubuntu: configurar servidor FTP en ubuntu server

Buenas a todos!
El programa que vamos a emplear como servidor ftp es vsftp, en un Ubuntu server.
Lo instalamos de la siguiente forma:
sudo apt-get install vsftpd
En el sistema operativo tenemos un usuario local llamado ftp_user, y queremos conectarnos con él a través de un cliente ftp.

El archivo de configuración de vsftp es /etc/vsftpd.conf y he fijado los siguientes atributos y valores:
listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list


Creamos el archivo que contendrá la lista de usuarios del ftp:
nano /etc/vsftpd.chroot_list

Y añadimos el usuario ftp_user.
#Usuarios
ftp_user


Para aplicar los cambios reiniciamos el servidor:
sudo /etc/init.d/vsftpd restart

Ahora vamos a añadir los permisos de escritura para el usuario ftp_user sobre los directorios del tomcat:

sudo usermod -a -G www-data ftp_user -a: el usuario se añadirá al grupo.
-G: el grupo al que se añadirá el usuario.
La instrucción hace que el usuario ftp_user se añada al grupo www-data.

sudo chgrp -R www-data /var/lib/tomcat7 -R: indica que el cambio será recursivo, afectará a los archivos y directorios recursivamente.
chgrp hace que el grupo propietario del directorio tomcat7 y sus subdirectorios archivos sea www-data.

sudo chmod -R g+w /var/lib/tomcat7 -R: indica que el cambio será recursivo.
g+w: significa que al grupo ("g") le añadimos ("+") el permiso de escritura ("w").

Y eso es todo! Con esto ya podréis subir archivos desde cualquier cliente FTP como FileZilla!
Espero que os sea útil!

jueves, 27 de marzo de 2014

HTML crear un link a la página principal, enlace a la home

Buenas a todos!
Para crear un link a la Home o a la página principal sólo hay que indicar la dirección como "/", esto indica al navegador que el enlace va al dominio principal:

<a href="/">Home</a>

Y ya está!

PHP: Problema session_start()

Buenas a todos!
Hay varias razones por las que session_start() puede generar problemas, la más común es debido a la codificación de carácteres del archivo .php en cuestión, si trabajamos con UTF-8, hay que asegurarse de que sea una codificación UTF-8 sin BOM, ya que de lo contrario se añaden unos carácteres antes de la declaración de session_start() y eso genera un error.

Los errores que suele indicarnos el servidor son:
Warning: Cannot modify header information - headers already sent by ...
Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent ...

Para ver qué codificación está usando nuestro archivo php, podemos emplear el Notepad++.
En la pestaña Codificación podemos cambiar la codificación de nuestro archivo a UTF-8 sin BOM.

Esto debería solucionar vuestro problema en caso de que fuera un tema de codificación.

Tened en cuenta de que session_start() debe ser la primera línea que escriba en el fichero php, ya que escribe los headers, no podéis poner ninguna instrucción de tipo echo antes que session_start(), eso también puede generar este tipo de errores.

Un saludo a todos!

miércoles, 19 de marzo de 2014

PHP: Borrar una variable de la sesión

Buenas a todos!
Borrar variables de la sesión en PHP puede ser algo muy importante, sobretodo en portales donde se deben reestablecer los valores iniciales del portal, o bien durante las etapas de desarrollo en las que debemos hacer pruebas constantes.

Por ejemplo, supongamos que tenemos una tienda virtual y hemos ido acumulando productos en una variable de sesión llamada 'cart', y una vez el cliente realiza el pago final debemos eliminar esta variable para que pueda volver a comprar. Evitando que se acumulen los nuevos artículos con los productos del pedido anterior.

unset($_SESSION['cart']);

Así de simple, unset nos permite eliminar variables específicas, en este caso le indicamos la variable de sesión 'cart'.

Ahora si comprobamos si está la variable en sesión con isset(), veremos que el resultado es false.

isset($_SESSION['cart']) dará como resultado false.

Un saludo a todos!

Comprobar si una variable existe en JavaScript

Comprobar si una variable existe o está definida en JavaScript puede es muy simple:

if(typeof variable == 'undefined'){
   //La variable no ha sido definida
}else{
   //La variable existe
}


Es importante diferenciar entre declaración de la variable y definición. La variable puede estar declarada pero no definida, lo que significa que no se le ha asignado ningún valor.

var variable;

if(typeof variable == 'undefined'){
   //La variable no ha sido definida
}else{
   //La variable existe
}


Esto indicará que la variable es undefined.
Así que realmente lo que comprobamos es si la variable está definida, ya que la variable puede existir pero no tener ningún valor asignado, en cuyo caso está no definida.

Un saludo a todos!

miércoles, 12 de febrero de 2014

Acceder a las propiedades de una función desde una función interna

Buenas a todos!

this se sobreescribe siempre que ejecutamos una nueva función en javascript.
Por esta razón, cuando queremos acceder desde una función interna a las propiedades de su parent (función padre), no podemos hacerlo mediante la palabra clave this.
Se puede acceder a sus propiedades, creando una variable en la función padre que tenga una copia de la instancia this. Así conseguimos ampliar el scope de this para que sea accesible desde la función interna.

function Parent(){
var self = this;
this.nombre = "parent";
var funcion_interna = function(){
this.nombre = "child";
alert(self.nombre + " " + this.nombre);
};
funcion_interna();
}

var p = new Parent();


La salida de esta función es: "parent child".

Este tipo de relaciones pueden ser útiles, cuando creamos funciones ajax o event handlers que deben trabajar con propiedades de instancia.

Un saludete para todos!

miércoles, 8 de enero de 2014

Error en ADB, el device está conectado pero pone offline

Buenas a todos,
El problema es simple, tenéis conectado el móvil al pc y cuando ejecutáis "adb devices", en la lista de dispositivos aparece lo siguiente:

List of devices attached
304D45C73C30202F offline

Al menos en mi caso, el problema radicaba en el cable usb de conexión, únicamente me servía para cargar el móvil. Lo cambié por otro, volví a ejecutar el comando "adb devices" y se conectó sin problemas.

List of devices attached
304D45C73C30202F device

Un saludo a todos!!