[OpenShift] Incluir BD en nuestra app

El siguiente paso, es incluir la BD, que no es del todo trivial:
Primero le indicamos que queremos incluir en nuestra aplicacion.
Con este comando vemos que nos dejan añadir, depende de la versión (Flex o express) pero seguro que esta mysql.

$ rhc-ctl-app -a MyApp -L

A continuación incluimos la BD y te saldrán los siguientes datos:

$ rhc-ctl-app -a MyApp -e add-mysql-5.1
Password:
Contacting https://openshift.redhat.com
Contacting https://openshift.redhat.com
API version:    1.1.1
Broker version: 1.1.1
RESULT:
Mysql 5.1 database added.  Please make note of these credentials:
Root User: admin
Root Password: ad3eR$4agk8z
Database Name: MyApp
Connection URL: mysql://127.1.1.10:3306/

Ahora pensaríamos que ya esta la bd, pero no, hay que modificar el fichero de build de la aplicación para que nos deje acceder. En la carpeta .openshift que se ha creado buscar:

.openshiftaction_hooksbuild

y copiar :

if ! /usr/bin/mysql -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" -e "show tables;" $OPENSHIFT_APP_NAME > /dev/null
then
/usr/bin/mysqladmin -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" create "$OPENSHIFT_APP_NAME"
fi
# Confirm database exists, if not create it
if ! /usr/bin/mysql -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" -e "show tables;" myapp > /dev/null
then
    echo
    echo "Database not found!  Creating and importing"
    echo
    /usr/bin/mysqladmin -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" create "myapp" 
    /usr/bin/mysql -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" myapp < "$OPENSHIFT_REPO_DIR/.openshift/action_hooks/bd.sql"
    echo
    echo "done."
else
    echo "Database found, skipping build"
fi

Solo hace falta cambiar myapp y el nombre del archivo sql con el que crear la bd. Así nos comunicamos directamente con el servidor y creamos nuestra bd.

Como bonus, hay que decir que las contraseñas y usuarios son variables del sistema con lo cual podemos referenciarlas así en nuestro código y no hay que tener que escribirlas.

define( "DB_SERVER",    $_ENV['OPENSHIFT_DB_HOST'] );
define( "DB_USER",      $_ENV['OPENSHIFT_DB_USERNAME'] );	
define( "DB_PASSWORD",  $_ENV['OPENSHIFT_DB_PASSWORD'] );

[OpenShift] Crear usuario, direccion y app

Hoy vamos a hablar de OpenShift de RedHat. OpenShift es un PaaS, es decir una plataforma para poder programar en la nube, es parecido a Google engine app, pero a diferencia, te dejan programar en Java, Perl, PHP, Python, and Ruby en su version Express y en su version Flex (avanzada) te dejan aparte, frameworks, y no-sql bd ( pero no he mirado cuanto cuesta).

Así aquí va una pequeña guia de como crearte un dominio y tu primera app, aparte de los problemas que he encontrado.
Para la guia sera en windows y con Cygwin, porque configuramos Openshift con ruby, así que nos bajamos Cygwin y le ponemos los paquetes que queramos, pero no olvides ruby.
Segun el tutorial de Openshift :

  • Prerequisites
    • Cygwin
    • The following optional cygwin components
      • openssh
      • ruby
      • make
      • gcc
      • git

Nos bajamos y extraemos rubygems from http://rubyforge.org/projects/rubygems, yo lo he descomprimido en el directorio tmp de cygwin. Y lo instalamos con:
$ ruby /setup.rb install

Despues instalamos el “gem” que nos deja manejar nuestra cuenta de Openshift:

$ gem install rhc

Ya tenemos todo, así que si no lo has hecho, ya puedes ir a registrarte a http://openshift.redhat.com/ y creo que se puede hacer por la web, pero yo me he creado el dominio desde la consola, escribiendo:

$ rhc-create-domain -n mydomain -l rhlogin

Y te pedira el password
Password: (type… type… type…)

Openshift te da un dominio y solo 1 por usuario! por tanto si me he registrado con user@fakemail.com y contraseña fakepw  y quiero que mi dominio sea gominola :D

sería $ rhc-create-domain -n gominola -l user@fakemail.com

Y crearas el dominio <nombredelapp>-gominola.rhcloud.com, es decir que se le añadira delante el nombre del app que crees.

Para crear un app :
$ rhc-create-app -a myapp -t php-5.3
Password: (type… type… type…)

en -t hay que elegir la librería con la que queremos programar ( yo lo elegí desde la web pero escribiendo $rhc-create-app -h te muestra la ayuda).

Edit: Mejor hacerlo desde comando para que te cree la carpeta con el proyecto, desde web tienes que lidiar con el git y me ha dado bastantes quebraderos.

Así que si creamos
$ rhc-create-app -a dulce -t php-5.3

tendremos dulce-gominola.rhcloud.com, al que podemos empezar a subir nuestra web. :D y eso es todo.
Hasta aquí me he quedado yo, si puedo pondré el siguiente paso de como desplegar nuestra app.

Problemas:

Durante la instalación me dio este error ruby :

C:cygwinlibruby1.8i386-cygwinreadline.so
to same address as parent(0x370000) != 0x2760000
C:cygwinbinruby.exe (3132): *** unable to remap

Para arreglarlo:
Salir de la consola de cygwin y entrar con la de windows (cmd)
navegar hasta c:cygwinbin
y escribir: ash rebaseall
Volver ha abrir la consola de cygwin y se supone que esta arreglado.

 

XNA – Deadvasion

Well, there are some screens of my game Deadvasion, the rules are clear you have to reach the city, without touch the bombs and if you want, use some brains for extra energy.

It’s my first game in XNA and Farseer, it’s not a big deal, but I learn quite a lot, in the future I ‘ll post some useful code and a video with the gameplay.
Capturatitulo gameplay

 

By the way, all the graphics was made by me.

Farseer, first approach

Farseer is a Physics Engine for XNA, I’m doing a little research, and I will use this post like a memo, with some links I’ve found:

  • http://farseerphysics.codeplex.com/documentation
  • http://www.flatredball.com/frb/docs/index.php?title=FlatRedBallXna:Tutorials:Farseer
  • http://www.sgtconker.com/2010/09/article-xna-farseer-platform-physics-tutorial/
  • http://www.andybeaulieu.com/Home/tabid/67/EntryID/89/Default.aspx
  • http://www.xnatutorial.com/?p=62
  • http://www.laumania.net/post/Getting-started-with-Farseer-Physics-Engine-1005-(Silverlight-2-beta-1).aspx
  • http://www.igda.org.my/gameinc/?s=farseer&searchsubmit=
  • http://www.farseergames.com/storage/farseerphysics/Manual2.1.htm

Tutorial básico de Android

Por fin termine mi “aplicación” no voy a seguir perfeccionandola por que no tiene sentido si el autor del comic no arregla el html de su web. Así que para aprender lo básico ha estado bien, aunque prefiero esforzarme en alguna aplicación más útil.

Voy a poner trozos de la aplicación que considero mas importantes y explicar para que son, así para quien le apetezca y para que no olvide como lo hice. Importante! es mi primera aplicación si hay algo que se hace mejor de otra forma o algún error o algo, por favor, no dudéis en comentarlo.

La aplicación consta de dos pantallas: Una que lee de un rss y muestra las últimas entradas ( Se que esta desordenado, pero ya he comentado que no voy a gastar mas tiempo en esta aplicación) y la siguiente es el visor de la imagen del comic ( Es un gif pero no consigo que cargue la animación, si alguien sabe como, que lo comente, me interesa mucho)

HSreader2

0.Como crear una lista desde un RSS

Para esta parte básicamente he utilizado el tutorial de esta web:  http://www.sgoliver.net/blog/?p=1588 esta muy explicado.

1. Crear una lista a medida

Para crear una lista personalizada, tenemos que utilizar un ListViewAdapter modificado por nosotros, y cambiar la actividad donde va estar la lista por ListActivity

//De
public class hsreader extends Activity {
//a
public class hsreader extends ListActivity {

Para dar forma a la lista se hace a partir de los XML, en el xml principal (main.xml) tenemos un text y la lista que queremos dar formato:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello"
    />
    <ListView android:id="@+id/android:list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

En este XML (log_template.xml) tenemos el formato de cada linea de la lista, hemos puesto 2 textview, pero podría ser cualquier cosa:

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
	<TextView
	android:id="@+id/row_toptext"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:singleLine="true"
	android:gravity="center_vertical"
	android:ellipsize="marquee"/>
	 <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:id="@+id/bottomtext"
            android:paddingTop="20dip"
            android:singleLine="false"
            android:ellipsize="marquee"
            android:textColor="#FFF"
        />

</RelativeLayout>

Y a continuación hay que llenar la lista:

//Log es una clase propia donde guardo los datos
//extraidos del RSS en un Hashmap
Log l = new Log();

//La lista estara compuesta de la clase Page
ArrayList<Page> datos= new ArrayList<Page>();

//LLenamos el array, para eso recorremos el
//Hashmap que hemos creado para guardar los
//objetos Page en la clase Log
Iterator it = l.getLog().entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry e = (Map.Entry)it.next();
        datos.add((Page) e.getValue());
     }

//lva es el Adapter creado como variable de la //clase
        lva= new ListViewAdapter(this, R.layout.log_template, datos);

//Buscamos la lista que queremos rellenar
        ListView myList=(ListView)findViewById(android.R.id.list);

//La rellenamos utilizando el adapter
        myList.setAdapter(this.lva);

Y ahora el adapter:

//Clase Adapter
public class ListViewAdapter extends ArrayAdapter<Page>{

//De lo que voy a llenar la lista
List <Page> items;
//Contexto
Context c;

//Constructor
	public  ListViewAdapter(Context context, int textViewResourceId, List<Page> items) {
		super(context,textViewResourceId,items);
		this.c=context;
	    this.items = items;
	}

//Esta es la función que rellena la lista, como
//vamos a cambiar el funcionamiento de como se
//rellena hay que sobrescribirla.
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
	View v = convertView;
	try{
	if (v == null) {
		//Si no hay vista hay que crearla
               //No estoy segura como funciona
	LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	v = vi.inflate(R.layout.log_template,null);
	}
        //Posicion tiene el item de la lista que se va
// a rrellenar
	Page o = items.get(position);
	if (o != null) {

	//poblamos la lista de elementos

	TextView tt = (TextView) v.findViewById(R.id.row_toptext);
	TextView t2= (TextView) v.findViewById(R.id.bottomtext);

//Comprobamos que existen los elementos y los
//rellenamos
//getURLpage() y getTitulo() son metodos de la //clase page
	if (t2!= null) {
	t2.setText(o.getURLpage());
	}
	if (tt != null) {
	tt.setText(o.getTitulo());
	}
	}
	}catch (Exception e) {
		System.out.print(e);
	}
	return v;

	}

}

Y con esto tenemos nuestra lista terminada!!! :)

2. Pasar de una actividad a otra

Parte básica de las aplicaciones android, pero por si alguien no lo tenia claro. A efectos prácticos una actividad es una pantalla de la aplicación. Para pasar de una a otra tenemos que poner este código en la principal.

try{
//p es información que queremos pasar a la otra actividad.
    	Page p = (Page) l.getItemAtPosition(position);

//Con intent le decimos la clase origen (hsreader.this)
//y la clase que queremos iniciar (Pageview.class)
    	 Intent intent = new Intent(hsreader.this, Pageview.class);

//Con un Bundle guardamos la informacion que queremos compartir
         Bundle bundle = new Bundle();
         bundle.putString("DIR", p.getURLpage().toString());
         bundle.putString("TITULO", p.getTitulo().toString());

//Incluimos el bundle al intent
         intent.putExtras(bundle);

//Iniciamos la actividad
         startActivity(intent);
    	}catch (Exception e) {
    	//Con Toast consegimos mostrar un mensaje por pantalla	Toast.makeText(this,e.toString(),Toast.LENGTH_LONG).show();
		}

Con esto se inicia la otra actividad y para sacar la información compartida:

//Recuperamos el bundle del intent
Bundle bundle = getIntent().getExtras();

//Y así extraemos la información que hay dentro
String titulo=bundle.getString("TITULO")

3. Leer desde un HTML

Esta solución la encontré visitando varias webs, ahora mismo no tengo la referencia si alguien lo sabe, la añado. Intentare explicar lo que pueda.

Se que la expresión regular es bastante “patatera” pero no quería entretenerme mucho.

//Las primeras lineas son para conectarse a la url y bajarse el HTML.
public void getHtml(String url) throws ClientProtocolException, IOException
	{
	    HttpClient httpClient = new DefaultHttpClient();
	    HttpContext localContext = new BasicHttpContext();
	    HttpGet httpGet = new HttpGet(url);
	    HttpResponse response = httpClient.execute(httpGet, localContext);
	    String result = "";

//Guardamos en la variable reader el HTML
	    BufferedReader reader = new BufferedReader(
	        new InputStreamReader(
	          response.getEntity().getContent()
	        )
	      );

	    String line = null;
	    int vez=0;
//Leemos cada linea y buscamos el patron
	    while ((line = reader.readLine()) != null &&vez==0){
//Buscamos una imagen
	    	  Pattern patron = Pattern.compile("<img src="http://www.mspaintadventures.com/storyfiles/hs2/.*");
	    	  Matcher matcher = patron.matcher(line);

	    	     // Hace que Matcher busque los trozos.
	    	     if(matcher.find()) // hay imagen
	    	     {
//Guardamos en el array los nombres de las imagenes y
//hacemos que deje de recorrer el fichero.
	    	         urlimg.add( line.substring(line.length()-9, line.length()));
	    	         vez=1;

	    	     }
	     //Si se recorriera el fichero compelo en result tendriamos el HTML.
	      result += line + "n";	     

	    }

	}

4. Descargar una imagen

Y para el final, el último reto de la aplicación:

try {

//urlimg es un Arraylist con los nombres de las imagenes
Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL("http://www.mspaintadventures.com/storyfiles/hs2/"+urlimg.get(0)).getContent());

//Buscamos donde vamos a poner la imagen
		  ImageView img = (ImageView) findViewById(R.id.comic);
//Colocamos la imagen			         img.setImageBitmap(bitmap);

} catch (MalformedURLException e) {
	 //log exception here
} catch (IOException e) {
	  //log exception here
}

Conclusión

A la aplicación le falta poder leer gif y flash, si alguien sabe como que lo diga :D.

Gracias por ver el post y espero que le sirva de ayuda a alguien.

[HSReader] Primera fase terminada

Después de unas horas peleándome he conseguido acceder al rss de la web MSPA y sacar los títulos de los comics y listar los en la aplicación.
Aunque no se muestra, también esta guardado la dirección web donde apunta, así que el siguiente paso sera encontrar las imágenes en la web. Para mostrarlo en la aplicación, el problema de este punto es que tengo que acceder al HTML y no hay ninguna etiqueta identificable de la ilustración. Más adelante la solucion :3.
Por ahora un screen de lo que he conseguido hoy ! a la izquierda el historial de comics de http://www.mspaintadventures.com y a la derecha mi aplicación.

HSreader1