<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Punto Flotante</title>
	<atom:link href="http://jcesar.artelogico.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://jcesar.artelogico.com</link>
	<description>Estará listo en seis meses así tengamos que trabajar en el por un año.</description>
	<lastBuildDate>Fri, 28 May 2010 15:45:02 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Sumar/restar fechas con Javascript</title>
		<link>http://jcesar.artelogico.com/2010/05/sumarrestar-fechas-con-javascript/</link>
		<comments>http://jcesar.artelogico.com/2010/05/sumarrestar-fechas-con-javascript/#comments</comments>
		<pubDate>Fri, 28 May 2010 15:45:02 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[javascript date datetime adddays]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=160</guid>
		<description><![CDATA[No encontré un ejemplo que sirviera pero leyendo la documentación me dí cuenta que se puede utilizar el constructor que acepta milisegundos:

var today = new Date();

// Sumar 7 días.
new Date(today.getTime() + (7 * 24 * 3600 * 1000)),

// Restar 5 días
new Date(today.getTime() - (5 * 24 * 3600 * 1000)),

Tenga en cuenta que esta solución [...]]]></description>
			<content:encoded><![CDATA[<p>No encontré un ejemplo que sirviera pero leyendo la documentación me dí cuenta que se puede utilizar el constructor que acepta milisegundos:</p>
<pre class="prettify">
var today = new Date();

// Sumar 7 días.
new Date(today.getTime() + (7 * 24 * 3600 * 1000)),

// Restar 5 días
new Date(today.getTime() - (5 * 24 * 3600 * 1000)),
</pre>
<p>Tenga en cuenta que esta solución ignora los <a href="http://es.wikipedia.org/wiki/Segundo_intercalar">segundos intercalares</a>. En mi caso no son necesarios pero puede que en el suyo si.</p>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2010/05/sumarrestar-fechas-con-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DataGrid de Silverlight 3 que agrega nuevas filas</title>
		<link>http://jcesar.artelogico.com/2009/11/datagrid-de-silverlight-3-que-agrega-nuevas-filas/</link>
		<comments>http://jcesar.artelogico.com/2009/11/datagrid-de-silverlight-3-que-agrega-nuevas-filas/#comments</comments>
		<pubDate>Sun, 01 Nov 2009 15:59:27 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=142</guid>
		<description><![CDATA[El DataGrid de Silverlight 3 es una contradicción: Por un lado es mucho más flexible que el de Windows Forms porque es muy fácil agregar cualquier control que queramos a una columna (Solo se agrega el control a la propiedad DataGridTemplateColumn) pero por otro es tan primitivo que no permite que el usuario agregue nuevas [...]]]></description>
			<content:encoded><![CDATA[<p>El DataGrid de Silverlight 3 es una contradicción: Por un lado <strong>es mucho más flexible que el de Windows Forms</strong> porque es muy fácil agregar cualquier control que queramos a una columna (Solo se agrega el control a la propiedad DataGridTemplateColumn) <strong>pero por otro es tan primitivo que no permite que el usuario agregue nuevas filas</strong> a la colección. </p>
<p>Para un proyecto que estoy realizando, agregar filas al DataGrid es una funcionalidad básica así que me puse a buscar la solución a este problema. La respuesta que dan por todos lados es agregar un elemento adicional a la colección y eliminarlo si el usuario lo dejó en blanco (Y prepararse para distinguir entre un objeto nuevo y uno modificado).</p>
<p>En mi caso, era una molestia agregar ese elemento en blanco ya que esta funcionalidad se necesitaba en muchos lugares. Así que, en vez de repetir esa lógica por cada DataGrid, decidí buscar la forma de obtener el mismo resultado sin tener que modificar la colección original. La solución a la que llegué me gustó tanto que decidí compartirla en este blog.</p>
<p>Este es el resultado:</p>
<div id="DataGridAddRow_before" style="text-align:center">
	<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="500" height="375"><param name="source" value="/wp-content/uploads/2009/10/DataGridAddRow_after.xap"/><param name="background" value="white" /><param name="minRuntimeVersion" value="3.0.40624.0" /><param name="autoUpgrade" value="true" /><a href="http://go.microsoft.com/fwlink/?LinkID=149156&#038;v=3.0.40624.0" style="text-decoration:none"><br />
			<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none"/><br />
		</a><br />
	</object>
</div>
<h4>Primero un micro-repaso del uso del DataGrid.</h4>
<p>Vamos a crear un nuevo proyecto Silverlight con el nombre DataGridAddRow y le decimos que no cree un proyecto Web ya que no lo necesitamos para probar. Abrimos MainPage.xaml y agregamos un DataGrid:</p>
<pre class="prettyprint">&lt;Grid x:Name="LayoutRoot" Margin="20"&gt;
    &lt;data:DataGrid x:Name="m_dgMovies"&gt;
    &lt;/data:DataGrid&gt;
&lt;/Grid&gt;</pre>
<p>En MainPage.xaml.cs está el código de la página. En el constructor le pasamos los datos al DataGrid. En este caso es una lista que estoy creando en el método ListOfPixarMovies() pero bien pueden ser datos que salen de un servicio web o algo así.</p>
<pre class="prettyprint">public partial class MainPage : UserControl
{
	public MainPage()
	{
		InitializeComponent();

		m_dgMovies.ItemsSource = ListOfPixarMovies();
	}

	private List&lt;Movie&gt; ListOfPixarMovies()
	{
		return new List&lt;Movie&gt;
		{
			new Movie { Name = "The Incredibles", Year = 2004 },
			new Movie { Name = "Chicken Little", Year = 2005 },
			new Movie { Name = "Ratatouille", Year = 2007 },
			new Movie { Name = "WALL·E", Year = 2008 },
			new Movie { Name = "Up", Year = 2009 },
		};
	}
}</pre>
<p>Y, por supuesto, tenemos que crear la clase Movie. <strong>El único requerimiento de esta solución es que la clase debe implementar INotifyPropertyChanged</strong> pero si uno está utilizando data binding para editar un objeto normalmente termina implementando INotifyPropertyChanged también. Esta es la clase que utilicé en el ejemplo:</p>
<pre class="prettyprint">public class Movie
		: System.ComponentModel.INotifyPropertyChanged
{
	string m_name;

	public string Name
	{
		get { return m_name; }
		set
		{
			m_name = value;
			OnPropertyChanged(new PropertyChangedEventArgs("Name"));
		}
	}

	int m_year;

	public int Year
	{
		get { return m_year; }
		set
		{
			m_year = value;
			OnPropertyChanged(new PropertyChangedEventArgs("Year"));
		}
	}

	public event PropertyChangedEventHandler PropertyChanged;

	protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
	{
		if (PropertyChanged != null)
			PropertyChanged(this, e);
	}
}</pre>
<p>Nada del otro mundo: Una clase con dos propiedades y cada vez que se modifican esas propiedades ejecutamos el evento PropertyChanged que requiere la interfaz INotifyPropertyChanged.</p>
<p>En este punto podemos ejecutar el proyecto y nos encontramos con un DataGrid con varias filas y podemos editar los datos pero no podemos agregar nuevas filas, como este:</p>
<div id="DataGridAddRow_before" style="text-align:center">
	<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="500" height="375"><param name="source" value="/wp-content/uploads/2009/10/DataGridAddRow_before.xap"/><param name="background" value="white" /><param name="minRuntimeVersion" value="3.0.40624.0" /><param name="autoUpgrade" value="true" /><a href="http://go.microsoft.com/fwlink/?LinkID=149156&#038;v=3.0.40624.0" style="text-decoration:none"><br />
			<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none"/><br />
		</a><br />
	</object>
</div>
<h4>La solución: AppendableCollection</h4>
<p>Para permitirle al usuario agregar nuevas filas todo lo que tenemos que hacer es agregar la clase <a href="/wp-content/uploads/2009/10/DataGridAddRow.zip">AppendableCollection</a> y en el constructor de la página modificamos la línea en la que pasábamos la lista de películas para envolverla con una instancia de AppendableCollection&lt;Movie&gt;:</p>
<pre class="prettyprint">public MainPage()
{
	InitializeComponent();

	//m_dgMovies.ItemsSource = ListOfPixarMovies();
	m_dgMovies.ItemsSource = new AppendableCollection&lt;Movie&gt;(ListOfPixarMovies());
}</pre>
<p><strong>El resultado es una fila vacía al final de los datos y el usuario ahora puede agregar nuevas filas editando esa fila vacía</strong>. Por lo menos hasta que salga una nueva versión del DataGrid con soporte para agregar nuevas filas, esta es probablemente la solución más sencillas para simular esta funcionalidad.</p>
<p>Realmente eso es todo lo que que hay que hacer: <strong>Agregar la clase, implementar INotifyPropertyChanged y envolver la colección en AppendableCollection</strong>. Ahora puede <a href="#descargar-la-clase-y-el-ejemplo">saltar hasta el final del artículo y descargar el código</a>. Para los tres que se quedaron, así es como funciona:</p>
<p>El DataGrid solo requiere que le pasemos un IEnumerable entonces AppendableCollection necesita implementar esa interfaz. En el método GetEnumerator() lo que hacemos es devolver el Enumerator de la colección original pero al final le agregamos la nueva instancia:</p>
<pre class="prettyprint">public class AppendableCollection&lt;T&gt;
	: System.Collections.Generic.IEnumerable&lt;T&gt;
	where T : System.ComponentModel.INotifyPropertyChanged, new()
{
	public IEnumerator&lt;T&gt; GetEnumerator()
	{
		return m_collection.Union(m_newItem).GetEnumerator();
	}

	readonly T[] m_newItem;
...
}</pre>
<p>Solo nos falta detectar cuando el usuario ha modificado el objeto. Por eso la clase de la colección debe implementar INotifyPropertyChanged. Cuando recibimos el evento de que una propiedad ha sido modificada agregamos la instancia actual a la colección original y creamos una nueva:</p>
<pre class="prettyprint">void newItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
	m_newItem[0].PropertyChanged -= newItem_PropertyChanged;
	m_collection.Add(m_newItem[0]);
	m_newItem[0] = new T();
	m_newItem[0].PropertyChanged += newItem_PropertyChanged;
}</pre>
<p>Solo nos falta avisarle al DataGrid que agregamos un nuevo elemento. Para eso implementamos la interfaz INotifyCollectionChanged y ejecutamos el evento CollectionChanged:</p>
<pre class="prettyprint">
public class AppendableCollection&lt;T&gt;
	: System.Collections.Generic.IEnumerable&lt;T&gt;
	, System.Collections.Specialized.INotifyCollectionChanged
	where T : System.ComponentModel.INotifyPropertyChanged, new()
{
	public event NotifyCollectionChangedEventHandler CollectionChanged;

	protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
	{
		if (CollectionChanged != null)
			CollectionChanged(this, e);
	}

	void newItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
	{
		m_newItem[0].PropertyChanged -= newItem_PropertyChanged;
		m_collection.Add(m_newItem[0]);
		m_newItem[0] = new T();
		m_newItem[0].PropertyChanged += newItem_PropertyChanged;
		OnCollectionChanged(new NotifyCollectionChangedEventArgs(
			NotifyCollectionChangedAction.Add, m_newItem[0],
			m_collection.Count));
	}
...
}</pre>
<h4 id="descargar-la-clase-y-el-ejemplo">Descargar la clase y el ejemplo</h4>
<p>El código de la clase está bajo licencia MIT y puede descargarse desde aquí: <a href="/wp-content/uploads/2009/10/DataGridAddRow.zip">DataGridAddRow.zip &#8211; Agregar nuevas filas a un DataGrid de Silverlight 3</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2009/11/datagrid-de-silverlight-3-que-agrega-nuevas-filas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Estrella Platino</title>
		<link>http://jcesar.artelogico.com/2009/09/estrella-platino/</link>
		<comments>http://jcesar.artelogico.com/2009/09/estrella-platino/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 22:16:12 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=137</guid>
		<description><![CDATA[Gracias a jalcom por avisarme:

]]></description>
			<content:encoded><![CDATA[<p>Gracias a <a href="http://jalcom.blogspot.com/">jalcom</a> por avisarme:</p>
<p><a href="http://jcesar.artelogico.com/wp-content/uploads/2009/09/estrella-platino.jpg" rel="shadowbox[post-137];player=img;"><img src="http://jcesar.artelogico.com/wp-content/uploads/2009/09/estrella-platino-300x215.jpg" alt="Microsoft Desarrollador Cinco Estrellas - Estrella Platino" title="Microsoft Desarrollador Cinco Estrellas - Estrella Platino" width="300" height="215" class="aligncenter size-medium wp-image-138" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2009/09/estrella-platino/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenGL ES 2D para Android</title>
		<link>http://jcesar.artelogico.com/2009/08/opengl-es-2d-para-android/</link>
		<comments>http://jcesar.artelogico.com/2009/08/opengl-es-2d-para-android/#comments</comments>
		<pubDate>Sun, 30 Aug 2009 00:05:00 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[opengl]]></category>
		<category><![CDATA[opengl-es]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=119</guid>
		<description><![CDATA[Estuve buscando un ejemplo sencillo de cómo inicializar OpenGL ES en Android con una proyección 2D, como para un juego de plataformas o algo así.
El Android SDK 1.5 incluye unos ejemplos de OpenGL, pero todos me parecieron innecesariamente complicados y es difícil comenzar un proyecto sencillo a partir de allí. Así que uní dos de [...]]]></description>
			<content:encoded><![CDATA[<p>Estuve buscando un ejemplo sencillo de cómo inicializar OpenGL ES en Android con una proyección 2D, como para un juego de plataformas o algo así.</p>
<p>El Android SDK 1.5 incluye unos ejemplos de OpenGL, pero todos me parecieron innecesariamente complicados y es difícil comenzar un proyecto sencillo a partir de allí. Así que uní dos de ellos (SpriteText y Triangle) y los simplifiqué de forma que fuera más sencillo ver todo el proceso.</p>
<p><strong>NOTA:</strong> Esto no es un tutorial de OpenGL. Voy a asumir que usted ya tiene algo de experiencia en OpenGL para así solo tener que explicar qué hace cada bloque de código y no función por función.</p>
<p>Al final de este ejemplo podremos mostrar una imagen centrada en la pantalla y girando como la del siguiente screenshot:</p>
<p><a href="http://jcesar.artelogico.com/wp-content/uploads/2009/08/android-opengl2d-sample.jpg" rel="shadowbox[post-119];player=img;"><img src="http://jcesar.artelogico.com/wp-content/uploads/2009/08/android-opengl2d-sample.jpg" alt="Android OpenGL ES 2D sample" title="Android OpenGL ES 2D sample" width="378" height="730" class="aligncenter size-full wp-image-121" /></a></p>
<p>Lo primero que vamos a hacer es crear un nuevo Activity y en el evento onCreate agregarle una vista GLSurfaceView:</p>
<pre class="prettyprint">
public class MainActivity extends Activity implements GLSurfaceView.Renderer {
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		mGLSurfaceView = new GLSurfaceView(this);
		mGLSurfaceView.setRenderer(this);
		setContentView(mGLSurfaceView);
	}
</pre>
<p>La llamada a setRenderer es porque en Android, todo el renderizado debe realizarlo una clase que implemente la interfaz GLSurfaceView.Renderer. Normalmente esto sería una clase separada pero para simplificar las cosas el mismo Activity implementa la interfaz y así le podemos pasar this.</p>
<p>Esta interfaz define tres métodos que implementaremos a continuación: onSurfaceCreated(), onSurfaceChanged() y onDrawFrame().</p>
<p>El primero, onSurfaceCreated(), se llama en cuanto la superficie esté lista para ser utilizada. Aquí incluiremos toda la inicialización que vayamos a hacer. Este método es un poco largo así que vamos por partes:</p>
<pre class="prettyprint">
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
	gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
	gl.glDisable(GL10.GL_DEPTH_TEST);
	gl.glDisable(GL10.GL_DITHER);
	gl.glDisable(GL10.GL_LIGHTING);

	gl.glEnable(GL10.GL_TEXTURE_2D);
	gl.glClearColor(0, 0, 0, 1);
	gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
</pre>
<p>Primero deshabilitamos algunas características de OpenGL ES que no necesitamos en 2D y luego habilitamos las texturas y limpiamos la pantalla.</p>
<p>Antes de continuar con el método vamos a ver las coordenadas que se utilizarán para dibujar la imagen.</p>
<p>En OpenGL ES no disponemos de las funciones glVertex3f() que se acostumbra utilizar en el OpenGL completo. En vez de eso se pasan todos las coordenadas de cada punto (vertex) en arreglos de floats y un arreglo de ushorts especifica el orden en que se dibujarán.</p>
<p>Esta técnica se conoce como VBO y en vez de explicar en detalle como funciona pueden leer el tutorial <a href="http://www.songho.ca/opengl/gl_vbo.html">OpenGL Vertex Buffer Object</a> de Song Ho Ahn que es excelente.</p>
<p>Estas son las coordenadas que utilicé:</p>
<pre class="prettyprint">
private static final int TEXTURE_WIDTH = 128;
private static final int TEXTURE_HEIGHT = 128;
private static final float[] sVertexValues = new float[] {
	-TEXTURE_WIDTH/2, -TEXTURE_HEIGHT/2, 0,
	 TEXTURE_WIDTH/2, -TEXTURE_HEIGHT/2, 0,
	-TEXTURE_WIDTH/2,  TEXTURE_HEIGHT/2, 0,
	 TEXTURE_WIDTH/2,  TEXTURE_HEIGHT/2, 0,
};
private static final float[] sTexCoordValues = new float[] {
	0, 1,
	1, 1,
	0, 0,
	1, 0,
};
private static final char[] sIndexValues = new char[] {
	0, 1, 2,
	1, 2, 3,
};
</pre>
<p>Como ven, sVertexValues es un cuadrado de 128 pixels centrado en (0,0). El cuadrado lo dibujamos utilizando dos triángulos que definimos en sIndexValues. Algo como esto.</p>
<p><a href="http://jcesar.artelogico.com/wp-content/uploads/2009/08/coordinates.png" rel="shadowbox[post-119];player=img;"><img src="http://jcesar.artelogico.com/wp-content/uploads/2009/08/coordinates.png" alt="Coordenadas para dibujar un cuadrado con OpenGL ES" title="Coordenadas para dibujar un cuadrado con OpenGL ES" width="180" height="180" class="aligncenter size-full wp-image-129" /></a></p>
<p>Es decir, sVertexValues son las coordenadas para A, B, C y D. De forma similar, sTexCoordValues es la posición de la textura y sIndexValues es el orden en que se deben utilizar los vertex para dibujar los dos triángulos: A, B y C para el primero y B, C y D para el segundo.</p>
<p>En cualquier lenguaje racional simplemente podríamos simplemente pasar esos arreglos a la función OpenGL y listo, pero en Java tenemos que evitar que garbage collector mueva los arreglos mientras estamos usándolos así que lo que hace el siguiente bloque de código es copiar las coordenadas a objetos Buffer:</p>
<pre class="prettyprint">
final int FLOAT_SIZE = 4;
final int CHAR_SIZE = 2;
mVertexBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * sVertexValues.length)
	.order(ByteOrder.nativeOrder()).asFloatBuffer();
mTexCoordBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * sTexCoordValues.length)
	.order(ByteOrder.nativeOrder()).asFloatBuffer();
mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * sIndexValues.length)
	.order(ByteOrder.nativeOrder()).asCharBuffer();

for (int i = 0; i &lt; sVertexValues.length; ++i)
	mVertexBuffer.put(i, sVertexValues[i]);
for (int i = 0; i &lt; sTexCoordValues.length; ++i)
	mTexCoordBuffer.put(i, sTexCoordValues[i]);
for (int i = 0; i &lt; sIndexValues.length; ++i)
	mIndexBuffer.put(i, sIndexValues[i]);
</pre>
<p>Yep. Es un bloque código bastante estúpido (e innecesario en cualquier otro lenguaje) pero lo necesitamos porque estamos programando en Java. Pero continuemos: Ahora vamos a cargar la textura (la imagen que vamos a mostrar):</p>
<pre class="prettyprint">
gl.glGenTextures(1, sTextureIDWorkspace, 0);
int textureID = sTextureIDWorkspace[0];

gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE);
</pre>
<p>Acabamos de crear una textura en memoria de video y le cambiamos algunas opciones de configuración.</p>
<pre class="prettyprint">
	Bitmap bitmap;
	InputStream is = getResources().openRawResource(R.drawable.robot);
	try {
		bitmap = BitmapFactory.decodeStream(is, null, sBitmapOptions);
	} finally {
		try {
			is.close();
		} catch (IOException e) {
			// Ignore
		}
	}

	GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
	bitmap.recycle();

	Runtime r = Runtime.getRuntime();
	r.gc();
}
</pre>
<p>Y en este bloque cargamos el bitmap desde un archivo de recursos (R.drawable.robot), lo convertimos al formato correcto y lo asignamos a la textura que habíamos creado. Finalmente es un buen momento para llamar al garbage collector.</p>
<p>Fiuuu. Por fin terminamos onSurfaceCreated(). Ese era el método más complicado. Ahora vamos a ver onSurfaceChanged(). Este método es llamado después de onSurfaceCreated() y cuando el usuario gira el teléfono así que es el lugar perfecto para configurar la proyección:</p>
<pre class="prettyprint">
public void onSurfaceChanged(GL10 gl, int width, int height) {
	gl.glViewport(0, 0, width, height);
	gl.glMatrixMode(GL10.GL_PROJECTION);
	gl.glLoadIdentity();
	gl.glOrthof(0, width, 0, height, 0, 1);
	gl.glShadeModel(GL10.GL_FLAT);
	gl.glEnable(GL10.GL_BLEND);
	gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
	gl.glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
	gl.glEnable(GL10.GL_TEXTURE_2D);
}
</pre>
<p>Aquí cambiamos la proyección a ortográfica que es la que se utiliza para dibujar en 2D y configuramos algunas cosas adicionales para las texturas.</p>
<p>En onDrawFrame() por fin vamos a dibujar algo.</p>
<pre class="prettyprint">
public void onDrawFrame(GL10 gl) {
	gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
	gl.glMatrixMode(GL10.GL_MODELVIEW);
	gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
	gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
	gl.glPushMatrix();
	gl.glLoadIdentity();
</pre>
<p>Este bloque es sencillo: Limpiamos la pantalla y le decimos a OpenGL ES que vamos a pasarle las coordenadas en arreglos (glEnableClientState() con GL_VERTEX_ARRAY y GL_TEXTURE_COORD_ARRAY). Le decimos también cual textura vamos a utilizar y finalmente nos aseguramos que estemos en (0,0).</p>
<pre class="prettyprint">
gl.glTranslatef(160, 240, 0);
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
gl.glRotatef(angle, 0, 0, 1.0f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexCoordBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, sIndexValues.length, GL10.GL_UNSIGNED_SHORT,
	mIndexBuffer);
</pre>
<p>Con eso nos movemos al centro de la pantalla y giramos la imagen según el milisegundo en el que nos encontremos. Enviamos las coordenadas a OpenGL y el se encarga de dibujar los dos triángulos.</p>
<pre class="prettyprint">
	gl.glPopMatrix();
	gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
</pre>
<p>Devolvemos todo a como lo encontramos y terminamos de pintar el frame.</p>
<p>Pueden descargar el <a href="http://jcesar.artelogico.com/wp-content/uploads/2009/08/OpenGL2D.zip">código de ejemplo de OpenGL ES 2D para Android SDK 1.5</a>. Está bajo la misma <a href="http://developer.android.com/sdk/download.html?v=android-sdk-windows-1.5_r3.zip">licencia del SDK</a> ya que está basado en los ejemplos que se incluyen allí.</p>
<p>El proyecto está para <a href="http://www.netbeans.org/">NetBeans</a> (Lo siento pero Eclipse me da muchos problemas) así que tendrán que instalar <a href="http://kenai.com/projects/nbandroid/pages/Install">NBAndroid</a> o importarlo manualmente en un proyecto nuevo de Eclipse.</p>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2009/08/opengl-es-2d-para-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Problemas actualizando XDebug en Windows (Solucionado)</title>
		<link>http://jcesar.artelogico.com/2009/07/problemas-actualizando-xdebug-en-windows-solucionado/</link>
		<comments>http://jcesar.artelogico.com/2009/07/problemas-actualizando-xdebug-en-windows-solucionado/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 00:25:03 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[xdebug]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=116</guid>
		<description><![CDATA[Llevo 3 horas desde que me dió por actualizar mi PC a PHP 5.3. Primero me ignoraba la opción zend_extension y no cargaba XDebug. Cuando PHP por fin la vió Apache se caía al abrir el primer script. La moraleja va primero: Si creen que VC9 es más nuevo y mejor se van a meter [...]]]></description>
			<content:encoded><![CDATA[<p>Llevo 3 horas desde que me dió por actualizar mi PC a PHP 5.3. Primero me ignoraba la opción zend_extension y no cargaba XDebug. Cuando PHP por fin la vió Apache se caía al abrir el primer script. La moraleja va primero: <strong>Si creen que VC9 es más nuevo y mejor se van a meter en un mundo de problemas.</strong></p>
<p>Para evitarles los mismos problemas (y sin recompilar nada) esto es lo que deben hacer:</p>
<p>Bajar la <a href="http://httpd.apache.org/download.cgi">versión oficial de Apache</a> que en este momento es la <a href="http://www.apache.org/dist/httpd/binaries/win32/apache_2.2.11-win32-x86-no_ssl.msi">versión 2.2.11</a>. Puede ser con o sin SSL aunque yo escogí sin SSL porque es más pequeña.</p>
<p>Ahora a descargar PHP. No descarguen PHP desde php.net/downloads.php si no desde <a href="http://windows.php.net/downloads">windows.php.net/downloads</a>. Allí dan muchas versiones pero la que nos interesa es <a href="http://windows.php.net/downloads/releases/php-5.3.0-Win32-VC6-x86.zip">VC6 x86 Thread Safe (El .ZIP)</a>.</p>
<p>Y finalmente XDebug. De nuevo hay que escoger la versión <a href="http://xdebug.org/files/php_xdebug-2.0.5-5.3-vc6.dll">5.3 VC6 (32 bit)</a>.</p>
<h3>Instalación de PHP en 1 minuto.</h3>
<p>Instale Apache (Next, Next, Next). Descomprima el .ZIP de PHP en C:\Program Files\php-5.3.0-Win32-VC6-x86 y copie XDebug a la misma carpeta.</p>
<p>Al final de C:\Program Files\Apache Software Foundation\Apache2.2\conf\httpd.conf pegue las siguientes líneas:</p>
<pre class="prettyprint">LoadModule php5_module "C:/Program Files/php-5.3.0-Win32-VC6-x86/php5apache2_2.dll"
AddType application/x-httpd-php .php
PHPIniDir "C:/Program Files/php-5.3.0-Win32-VC6-x86"</pre>
<p>Ahora en la carpeta de PHP renombre php.ini-development a solamente php.ini y al comienzo del archivo pegue las siguientes líneas:</p>
<pre class="prettyprint">zend_extension="C:\Program Files\php-5.3.0-Win32-VC6-x86\php_xdebug-2.0.5-5.3-vc6.dll"
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_port=9000
cgi.force_redirect = 0</pre>
<p>Ahora podemos probar ejecutando phpinfo():</p>
<pre class="prettyprint">&lt;?php phpinfo() ?&gt;</pre>
<p>En esa página debería salir el logo de XDebug junto al de PHP.</p>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2009/07/problemas-actualizando-xdebug-en-windows-solucionado/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NOTA MENTAL: Apagar el cache antes de optimizar un SELECT en MySQL</title>
		<link>http://jcesar.artelogico.com/2009/06/nota-mental-apagar-el-cache-antes-de-optimizar-un-select-en-mysql/</link>
		<comments>http://jcesar.artelogico.com/2009/06/nota-mental-apagar-el-cache-antes-de-optimizar-un-select-en-mysql/#comments</comments>
		<pubDate>Mon, 01 Jun 2009 23:41:55 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=86</guid>
		<description><![CDATA[Ayer estaba tratando de averiguar por qué el sitio web de un amigo producía errores esporádicos como este: Fatal error: Maximum execution time of 30 second exceeded in ...
Estaba sospechando de una petición que se veía muy mal escrita. Era similar a esta:
select *
	from film a
	where a.description in
		(select description
			from film b
			where b.description >= a.description)
	order by [...]]]></description>
			<content:encoded><![CDATA[<p>Ayer estaba tratando de averiguar por qué el sitio web de un amigo producía errores esporádicos como este: <code>Fatal error: Maximum execution time of 30 second exceeded in ...</code></p>
<p>Estaba sospechando de una petición que se veía muy mal escrita. Era similar a esta:</p>
<pre class="prettyprint">select *
	from film a
	where a.description in
		(select description
			from film b
			where b.description >= a.description)
	order by extract(year from a.last_update),
	extract(month from a.last_update)</pre>
<p>Sin embargo, al ejecutarla en el <a href="http://dev.mysql.com/downloads/gui-tools/">MySQL Query Browser</a> la petición <strong>se ejecutaba en 0.06 segundos</strong> aproximadamente. ¡Seis centésimas de segundo! WTF?!</p>
<p>Resulta que luego de la primera ejecución MySQL almacena tanto la petición como los resultados en un cache y la próxima vez que alguien ejecuta la misma petición simplemente trae los mismos resultados.</p>
<p><strong>Para deshabilitar el cache</strong> para una sola petición y así poder ver cuánto tiempo se está demorando en realidad <strong>hay que agregar la opción <code>SQL_NO_CACHE</code></strong> al comienzo del <code>select</code>: </p>
<pre class="prettyprint">select SQL_NO_CACHE *
	from film a
	where a.description in
		(select description
			from film b
			where b.description >= a.description)
	order by extract(year from a.last_update),
	extract(month from a.last_update)</pre>
<p>Después de agregar la opción <code>SQL_NO_CACHE</code> la petición se demoraba <strong>siempre los mismos 82 segundos</strong> (con razón superaba el límite de 30 segundos de PHP). Así pudimos observar cuál era el problema y solucionarlo rápidamente.</p>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2009/06/nota-mental-apagar-el-cache-antes-de-optimizar-un-select-en-mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Transformar URLs virtuales en absolutos con ASP.NET</title>
		<link>http://jcesar.artelogico.com/2009/05/transformar-urls-virtuales-en-absolutos-con-aspnet/</link>
		<comments>http://jcesar.artelogico.com/2009/05/transformar-urls-virtuales-en-absolutos-con-aspnet/#comments</comments>
		<pubDate>Wed, 27 May 2009 17:43:20 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[c#]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=72</guid>
		<description><![CDATA[Una de las ventajas que tiene ASP.NET sobre otras plataformas de desarrollo es que las aplicaciones son auto-contenidas en proyectos y al administrador del servidor se le facilita instalarlas en diferentes áreas de un sitio web.
Claro, esto solo funciona si la aplicación fue desarrollada teniendo en cuenta que puede quedar instalada en diferentes carpetas, porque [...]]]></description>
			<content:encoded><![CDATA[<p>Una de las ventajas que tiene ASP.NET sobre otras plataformas de desarrollo es que las aplicaciones son auto-contenidas en proyectos y al administrador del servidor se le facilita instalarlas en diferentes áreas de un sitio web.</p>
<p>Claro, esto solo funciona si la aplicación fue desarrollada teniendo en cuenta que puede quedar instalada en diferentes carpetas, porque si el desarrollador dejó URLs fijos en algún lado esa parte de la aplicación se va a dañar si no se instala en la misma carpeta.</p>
<p>Por ejemplo, si el logo de la aplicación está en <code>"/Images/logo.png"</code> y el desarrollador puso el URL fijo desde la raíz, cuando la aplicación se instale en otra carpeta el logo no va a aparecer.</p>
<p>¿Cómo evitamos este problema? Fácil: utilizando URLs virtuales que ASP.NET luego transforma en absolutos dependiendo de la carpeta donde se haya instalado la aplicación. Por ejemplo, si especificamos el logo de esta forma:</p>
<pre class="prettyprint">
&lt;asp:Image ID="iLogo" runat="server" ImageUrl="~/Images/Logo.png" /&gt;
</pre>
<p>ASP.NET lo convertirá automáticamente en una etiqueta <code>&lt;IMG&gt;</code> con el URL apropiado dependiendo de la carpeta donde se haya instalado la aplicación.</p>
<p>Los controles que necesitan URLs hacen esta conversión por nosotros cuando es apropiado. Pero ¿Cómo utilizar URLs virtuales cuando no estamos usando controles? Por ejemplo, en una etiqueta <code>&lt;LINK&gt;</code> o <code>&lt;SCRIPT&gt;</code>.</p>
<p>En el fichero .ASPX o en el code-behind podemos usar el método <code>ResolveClientUrl()</code> que realiza la misma función. Por ejemplo, en una etiqueta <code>&lt;SCRIPT&gt;</code> podemos hacer esto:</p>
<pre class="prettyprint">
&lt;script src="&lt;%= ResolveClientUrl("~/Scripts/effects.js") %&gt;" type="text/javascript"&gt;
&lt;/script&gt;
</pre>
<p>Este método está definido en la clase Control y tanto Page como UserControl hereda en algún punto de Control.</p>
<p>Ahora, ¿Como transformar un URL virtual en una clase que no hereda de Control? Por ejemplo en una clase Presenter que debe transformar URLs virtuales almacenados en la base de datos.</p>
<p>En estos casos podemos utilizar los métodos estáticos de la clase <code>VirtualPathUtility</code>. Por ejemplo, suponga que tengo una lista con los URLs de documentos adjuntos que quiero pasar a la vista transformados en URLs absolutos. Lo puedo hacer de esta forma:</p>
<pre class="prettyprint">
// En el Presenter
public string Attachments
{
    get
    {
        foreach (var url in m_attachments)
            yield return VirtualPathUtility.ToAbsolute(url);
    }
}
</pre>
<p>Utilizando URLs virtuales podemos asegurarnos que nuestra aplicación va a funcionar de la misma forma ya sea que la instalen en la raíz del sitio web como si la instalan en otra carpeta y como vieron ASP.NET nos facilita bastante el trabajo con los diferentes métodos para transformarlos.</p>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2009/05/transformar-urls-virtuales-en-absolutos-con-aspnet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Comentarios condicionales para mantener la cordura</title>
		<link>http://jcesar.artelogico.com/2009/05/comentarios-condicionales-para-mantener-la-cordura/</link>
		<comments>http://jcesar.artelogico.com/2009/05/comentarios-condicionales-para-mantener-la-cordura/#comments</comments>
		<pubDate>Wed, 27 May 2009 15:23:29 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[ie]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=66</guid>
		<description><![CDATA[Si pudiéramos convencer a nuestros clientes de que deben actualizar sus browsers esta página probablemente no sería necesaria, pero como Internet Explorer 6 (un programa que salió en el 2001) todavía es ampliamente utilizado hay que mantener los sitios compatibles con estos browsers antiguos.
Crear un sitio web que se vea igual en diferentes browsers puede [...]]]></description>
			<content:encoded><![CDATA[<p>Si pudiéramos convencer a nuestros clientes de que deben actualizar sus browsers esta página probablemente no sería necesaria, pero como Internet Explorer 6 (un programa que salió en el 2001) todavía es ampliamente utilizado hay que mantener los sitios compatibles con estos browsers antiguos.</p>
<p>Crear un sitio web que se vea igual en diferentes browsers puede hacer que un desarrollador web pierda la razón cuando llegue el momento de corregir los problemas que se presentan en Internet Explorer.</p>
<p><strong>Mi método para crear un sitio web es armar el diseño en Firefox</strong> (porque con <a href="http://getfirebug.com/">Firebug</a> y <a href="https://addons.mozilla.org/en-US/firefox/addon/60">Developer Toolbar</a> tiene el mejor ambiente de desarrollo) hasta que se ve igual a la imagen que me entrega el diseñador. <strong>A continuación pruebo en Safari y Chrome</strong> con los cuales casi nunca tengo que cambiar nada.</p>
<p><strong>Pero luego llega la hora de probar con Internet Explorer 6 y 7 y lo más probable es que el diseño esté completamente destrozado.</strong> Una columna debajo de la otra y con diferentes anchos, fondos y fuentes que no son los correctas, PNGs sin transparencia. Todo esto muy común en versiones anteriores de Internet Explorer.</p>
<p>Se puede probar agregando hacks al CSS (secuencias de caracteres que debido a bugs en los mismos browsers permiten entregar código diferente a algunos browsers) pero siempre me ha quedado un mal sabor de boca al usar estos hacks ya que el código CSS se convierte en un desorden y, claro, ya no valida.</p>
<p>La forma más sencilla que he encontrado es colocar comentarios condicionales al HTML para que diferentes versiones de Internet Explorer carguen hojas de estilo adicionales. Por ejemplo, en la cabecera de la página uno puede colocar:</p>
<pre class="prettyprint">
&lt;link href="general.css" media="screen" rel="stylesheet" type="text/css" /&gt;
&lt;!--[if lte IE 7]&gt;&lt;link href="ie7below.css" rel="stylesheet" type="text/css" /&gt;&lt;![endif]--&gt;
&lt;!--[if lte IE 6]&gt;&lt;link href="ie6below.css" rel="stylesheet" type="text/css" /&gt;&lt;![endif]--&gt;</pre>
<p>En este caso, <strong>Firefox, Safari, Chrome e Internet Explorer 8 verán solo la primera hoja de estilos (general.css)</strong>. <strong>Internet Explorer 7 verá general.css e ie7below.css</strong> y en esta última agregaremos lo que necesitemos para arreglar la página. Finalmente <strong>Internet Explorer 6 verá las tres hojas de estilo</strong> y en ie6below.css agregaremos las reglas específicas para IE6.</p>
<p>Veamos cómo funciona: Suponiendo que tenemos el siguiente código HTML:</p>
<pre class="prettyprint">
&lt;div id="wrapper"&gt;
	&lt;div id="sidebar"&gt;
		&lt;ul&gt;
			&lt;li&gt;&lt;a href="/"&gt;Inicio&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;

	&lt;div id="content"&gt;
		&lt;p&gt;Bienvenido a mi sitio web.&lt;/p&gt;
	&lt;/div&gt;
&lt;/div&gt;
</pre>
<p>&#8230; y queremos que se vea como dos columnas de contenido, podemos hacer algo como esto para los browsers modernos (Firefox, Safari, IE8):</p>
<pre class="prettyprint">
/* general.css */
#wrapper {
	margin: 0 auto;
	overflow: hidden;
	width: 970px;
        margin
}
#sidebar {
	background-color: #CCC;
	float: left;
	padding: 10px 15px;
	width: 150px;
}
#content {
	background-color: #EFEFEF;
	margin-left: 180px;
	padding: 10px 15px;
}
</pre>
<p>En Internet Explorer 8 el diseño ya se ve como en esta imagen:</p>
<p><a href="http://jcesar.artelogico.com/wp-content/uploads/2009/05/ie8.png" rel="shadowbox[post-66];player=img;"><img src="http://jcesar.artelogico.com/wp-content/uploads/2009/05/ie8-300x49.png" alt="ie8" title="ie8" width="300" height="49" class="aligncenter size-medium wp-image-102" /></a></p>
<p>Ahora probemos en Internet Explorer 7 y por supuesto, el &#8220;margin: 0 auto&#8221; que utilizo para centrar las columnas en la página no funciona y los espacios en el sidebar están diferentes:</p>
<p><a href="http://jcesar.artelogico.com/wp-content/uploads/2009/05/ie7.png" rel="shadowbox[post-66];player=img;"><img src="http://jcesar.artelogico.com/wp-content/uploads/2009/05/ie7-300x49.png" alt="ie7" title="ie7" width="300" height="49" class="aligncenter size-medium wp-image-104" /></a></p>
<p>Para arreglarlo abrimos ie7below.css y agregamos el siguiente código:</p>
<pre class="prettyprint">
body { text-align: center }
#wrapper { text-align: left }
#sidebar { zoom: 1 }
</pre>
<p>Ahora probamos en Internet Explorer 6 y vemos que las columnas tienen diferentes anchos:</p>
<p><a href="http://jcesar.artelogico.com/wp-content/uploads/2009/05/ie6.png" rel="shadowbox[post-66];player=img;"><img src="http://jcesar.artelogico.com/wp-content/uploads/2009/05/ie6-300x49.png" alt="ie6" title="ie6" width="300" height="49" class="aligncenter size-medium wp-image-103" /></a></p>
<p>Esto es porque en IE6 hay que incluir el padding en el ancho de la columna. Entonces cambiamos los anchos en el archivo ie6below.css:</p>
<pre class="prettyprint">
#wrapper { width: 590px }
#sidebar { width: 130px }
</pre>
<p>Perfecto, ya se ve igual en estas tres versiones de Internet Explorer.</p>
<p><strong>Utilizando comentarios condicionales mantenemos nuestra hoja de estilo general mucho más sencilla</strong> (la que funciona en browsers modernos) <strong>y aun así nos aseguramos que versiones anteriores de Internet Explorer funcionen correctamente</strong>.</p>
<p>Para mayor información sobre los comentarios condicionales les recomiendo visitar <a href="http://www.quirksmode.org/css/condcom.html">Quirks Mode &#8211; Conditional Comments</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2009/05/comentarios-condicionales-para-mantener-la-cordura/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Paginación estilo Digg con MySQL y PHP</title>
		<link>http://jcesar.artelogico.com/2009/05/paginacion-estilo-digg-con-mysql-y-php/</link>
		<comments>http://jcesar.artelogico.com/2009/05/paginacion-estilo-digg-con-mysql-y-php/#comments</comments>
		<pubDate>Fri, 22 May 2009 23:45:44 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=35</guid>
		<description><![CDATA[Cuando se tiene una buena cantidad de resultados es conveniente presentarlos al usuario página por página para facilitar la navegación. Esto es algo que se pregunta a menudo en los foros de PHP &#8220;Tengo una petición que me regresa muchos registros. ¿Cómo separo los resultados en varias páginas?&#8221;.
En este tutorial voy a mostrar un método [...]]]></description>
			<content:encoded><![CDATA[<p>Cuando se tiene una buena cantidad de resultados es conveniente presentarlos al usuario página por página para facilitar la navegación. Esto es algo que se pregunta a menudo en los foros de PHP <em>&#8220;Tengo una petición que me regresa muchos registros. ¿Cómo separo los resultados en varias páginas?&#8221;</em>.</p>
<p>En este tutorial voy a mostrar un método para dividir los resultados en varias páginas y al final le daremos un estilo similar a Digg. Lo que queremos obtener es un listado de 12 películas por página y en la parte inferior enlaces a páginas similar al que usa <a href="http://digg.com">Digg</a>, que se ven así:</p>
<p><a href="http://jcesar.artelogico.com/wp-content/uploads/2009/05/digg.png" rel="shadowbox[post-35];player=img;"><img src="http://jcesar.artelogico.com/wp-content/uploads/2009/05/digg.png" alt="digg" title="digg" width="520" height="100" class="aligncenter size-full wp-image-37" /></a></p>
<p>Para efectos de demostración voy a utilizar la <a href="http://downloads.mysql.com/docs/sakila-db.zip">base de datos Sakila</a> que es una base de datos de ejemplo desarrollada para MySQL. Específicamente queremos mostrar la información de las películas almacenadas en la tabla film.</p>
<p>A continuación voy a discutir este <a href='http://jcesar.artelogico.com/wp-content/uploads/2009/05/indexphp.txt'>script de ejemplo de paginación estilo Digg con MySQL y PHP</a>. Para probarlo en su equipo deberá tener instalado Sakila. Guárdelo en una carpeta de su servidor web y cambie los datos de la conexión a la base de datos que se encuentran al comienzo:</p>
<pre class="prettyprint">
$hostname    = 'localhost';
$username    = 'root';
$password    = '123456';
$database    = 'sakila';
</pre>
<h4>Las consultas</h4>
<p>Primero necesitamos hacer una consulta para obtener el número de registros en la tabla y lo almacenamos en una variable <code>$filmsCount</code>:</p>
<pre class="prettyprint">
select count(*) filmsCount
	from film
</pre>
<p>Ahora calculamos el número máximo de páginas que podemos mostrar. Para esto utilizamos el número de registros que acabamos de obtener y lo dividimos entre el número de registros por página. Aquí estoy usando la función ceil(), que redondea el numero hacia arriba, porque también tenemos que contar la última página que puede quedar con menos registros que las demás.</p>
<pre class="prettyprint">
$pagesCount = (int)ceil($filmsCount / $rowCount);
</pre>
<p>Ahora averiguamos en qué página estamos. En el URL va a venir un parámetro <code>pageIndex </code>con el índice de la página. Si no está presente suponemos que estamos en la primer página y si sobrepasa la última página suponemos que estamos en la página actual.</p>
<pre class="prettyprint">
$pageIndex = isset($_REQUEST['pageIndex']) ? (int)$_REQUEST['pageIndex'] : 0;
if ($pageIndex >= $pagesCount)
	$pageIndex = $pagesCount - 1;
</pre>
<p>Estamos listos para obtener los registros de la página. El <code>SELECT</code> de MySQL tiene unos parámetros justo para esto. Se pasan con la cláusula <code>LIMIT</code> de esta forma</p>
<pre class="prettyprint">
$offset = $pageIndex * $rowCount;
$sql = "
select *
	from film
	order by title
	limit $offset, $rowCount
";
</pre>
<p><code>$rowCount</code> es el número de registros por página y puede ser el número que usted quiera. En el ejemplo estoy usando 12. Los registros los almaceno como objetos en un arreglo <code>$films</code> y luego recorro el arreglo para mostrar cada registro.</p>
<h4>Los enlaces de las páginas</h4>
<p>Ahora la parte más delicada: Mostrar el listado de páginas con el estilo de Digg. Vamos a crear una lista <code>&lt;UL&gt;</code> donde cada elemento va a ser un enlace a la página correspondiente.</p>
<p>El enlace a la página anterior es el más sencillo. Simplemente, si estamos en una página mayor a la primera mostramos el enlace:</p>
<pre class="prettyprint">
&lt;ul id="pages"&gt;
&lt;?php
// Página anterior.
if ($pageIndex &gt; 0) {
?&gt;
	&lt;li class="page"&gt;&lt;a href="?pageIndex=&lt;?php echo $pageIndex - 1 ?&gt;"&gt;&amp;lquo;&lt;/a&gt;&lt;/li&gt;
&lt;?php } ?&gt;
</pre>
<p>Ahora mostraríamos la página actual rodeada de N páginas adelante y atrás. El número de páginas a mostrar lo guardo en la variable <code>$pagesToShow</code>. Entonces calculamos las páginas que se van a mostrar así:</p>
<pre class="prettyprint">
$start = $pageIndex - $pagesToShow;
if ($start &lt; 0)
	$start = 0;

$end = $pageIndex + $pagesToShow;
if ($end &gt;= $pagesCount)
	$end = $pagesCount - 1;
</pre>
<p><code>$start</code> y <code>$end</code> los usaremos luego en un ciclo; sin embargo, hay que tener en cuenta la primera y segunda página. En Digg siempre se muestran los enlaces de la primera y segunda página. No importa si uno está en la página 500, siempre se muestran. Entonces los mostramos teniendo en cuenta que no se pueden repetir después:</p>
<pre class="prettyprint">
if ($start &gt; 0) {
	for ($i = 0; $i &lt; 2 &amp;&amp; $i &lt; $start; ++$i) {
?&gt;
	&lt;li class="page"&gt;&lt;a href="?pageIndex=&lt;?php echo $i ?&gt;"&gt;&lt;?php echo $i + 1 ?&gt;&lt;/a&gt;&lt;/li&gt;
&lt;?php
	}
}
</pre>
<p>Ahora si podemos mostrar las páginas con toda tranquilidad. Lo único que tenemos que tener en cuenta es que a la página actual no le ponemos enlace:</p>
<pre class="prettyprint">
for ($i = $start; $i &lt;= $end; ++$i) {
	if ($pageIndex == $i) {
?&gt;
	&lt;li class="page current"&gt;&lt;?php echo $i + 1 ?&gt;&lt;/li&gt;
&lt;?php
	} else {
?&gt;
	&lt;li class="page"&gt;&lt;a href="?pageIndex=&lt;?php echo $i ?&gt;"&gt;&lt;?php echo $i + 1 ?&gt;&lt;/a&gt;&lt;/li&gt;
&lt;?php
	}
}
</pre>
<p>Ya vamos terminando&#8230; De forma similar a la primera y segunda página, la penúltima y última siempre se muestran. Pero tenemos que evitar repetirlas así que usamos la función <code>max()</code> para evitarlo:</p>
<pre class="prettyprint">
if ($end &lt; $pagesCount - 1) {
	for ($i = max($pagesCount - 2, $end + 1); $i &lt; $pagesCount; ++$i) {
?&gt;
	&lt;li class="page"&gt;&lt;a href="?pageIndex=&lt;?php echo $i ?&gt;"&gt;&lt;?php echo $i + 1 ?&gt;&lt;/a&gt;&lt;/li&gt;
&lt;?php
	}
}
</pre>
<p>Y para finalizar mostramos el enlace a la página siguiente que es bastante sencillo y cerramos el <code>&lt;UL&gt;</code>:</p>
<pre class="prettyprint">
&lt;?php
// Siguiente página
if ($pageIndex &lt; $pagesCount) {
?&gt;
	&lt;li class="page"&gt;&lt;a href="?pageIndex=&lt;?php echo $pageIndex + 1 ?&gt;"&gt;&amp;gt;&lt;/a&gt;&lt;/li&gt;
&lt;?php } ?&gt;
&lt;/ul&gt;
</pre>
<p>Ahora necesitamos algo de CSS para que se parezca al de Digg. Lo que tenemos que hacer cambiar la lista de dirección vertical a horizontal con un <code>display: inline;</code> para los elementos, agregar los bordes, unos paddings y estamos listos. Este es el código CSS que yo utilicé en el ejemplo:</p>
<pre class="prettyprint">
#pages {
	clear: both;
	text-align: center;
}
#pages li {
	display: inline;
	padding: 3px 6px 4px;
}
#pages li.page {
	border: 1px solid #CCC;
}
#pages li.current {
	background-color: #CCC;
}
</pre>
<p>El resultado final es una página como la de la captura de pantalla en la que podemos ver 12 películas por páginas y usar los enlaces de la parte inferior para navegar por las páginas.</p>
<p><a href="http://jcesar.artelogico.com/wp-content/uploads/2009/05/paginacion-estilo-digg.png" rel="shadowbox[post-35];player=img;"><img src="http://jcesar.artelogico.com/wp-content/uploads/2009/05/paginacion-estilo-digg-300x246.png" alt="paginacion-estilo-digg" title="paginacion-estilo-digg" width="300" height="246" class="aligncenter size-medium wp-image-46" /></a></p>
<p>En una aplicación más grande, la lógica necesaria para mostrar los enlaces de las páginas debería encapsularse en una clase para evitar errores cuando se desee reutilizar en otro listado y el HTML podría guardarse en una plantilla separada. Este ejercicio se lo dejo quienes lean este blog&#8230; si, cualquiera de ustedes tres.</p>
<p><strong>ACTUALIZACIÓN 2009/05/29:</strong> Como correctamente apunta <a href="http://jalcom.blogspot.com/">Jairo</a>, a los enlaces de la paginación hay que agregarle cualquier parámetro que modifique los resultados del <code>SELECT</code>. Por ejemplo, si hay que filtrar los films por el precio deberíamos pasarlo al final del URL así:</p>
<pre class="prettyprint">
&lt;?php
// Siguiente página
if ($pageIndex &lt; $pagesCount) {
?&gt;
	&lt;li class="page"&gt;&lt;a href="?pageIndex=&lt;?php echo $pageIndex + 1,
		'&amp;price=', $price ?&gt;"&gt;&amp;gt;&lt;/a&gt;&lt;/li&gt;
&lt;?php } ?&gt;
&lt;/ul&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2009/05/paginacion-estilo-digg-con-mysql-y-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Eliminando el borde gris de Flash</title>
		<link>http://jcesar.artelogico.com/2009/05/eliminando-el-borde-gris-de-flash/</link>
		<comments>http://jcesar.artelogico.com/2009/05/eliminando-el-borde-gris-de-flash/#comments</comments>
		<pubDate>Fri, 22 May 2009 01:00:27 +0000</pubDate>
		<dc:creator>jcarrascal</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[ie]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://jcesar.artelogico.com/?p=15</guid>
		<description><![CDATA[Debido a que EOLAS demandó a Microsoft por una patente&#8230; Pausa para apreciar la ironía&#8230; Internet Explorer comenzó a agregar un borde gris alrededor de cualquier película flash y solo se elimina al hacerle clic para activarlas.
Este es el método más sencillo para eliminar ese molesto borde gris en las animaciones flash. Fué inventado por [...]]]></description>
			<content:encoded><![CDATA[<p>Debido a que EOLAS demandó a Microsoft por una patente&#8230; <em>Pausa para apreciar la ironía&#8230;</em> Internet Explorer comenzó a agregar un borde gris alrededor de cualquier película flash y solo se elimina al hacerle clic para activarlas.</p>
<p>Este es el método más sencillo para eliminar ese molesto borde gris en las animaciones flash. Fué inventado por <a href="http://latrine.dgx.cz/how-to-avoid-activation-of-active-x-in-ie">Tohle Býval</a> y no podría ser más sencillo: Solo hay que incluir un script en la cabecera de la página.</p>
<p>IMPORTANTE: Antes de continuar, debo aclarar que este método <strong>solo funciona si se está abriendo la página desde un servidor web</strong>. Puede ser Apache o IIS montado en el mismo equipo o también el servidor de hosting que usted tenga. <strong>Pero si prueban a abrir el HTML diréctamente desde el disco no va a funcionar</strong>.</p>
<p>Bueno, no más preámbulos. Justo antes de cerrar la etiqueta &lt;head&gt; hay que agregar el siguiente código:</p>
<pre class="prettyprint">&lt;!--[if IE]&gt;
&lt;script type="text/javascript" src="fix_eolas.js"
	defer="defer"&gt;&lt;/script&gt;
&lt;![endif]--&gt;
&lt;/head&gt;</pre>
<p>Es de vital importancia que mantengan el <strong>defer=&#8221;defer&#8221;</strong> para que el script se ejecute cuando todas las películas ya hayan cargado. Además usamos comentarios condicionales para que solo Internet Explorer vea el script.</p>
<p>En esa etiqueta nos referimos a este archivo <a href="http://jcesar.artelogico.com/wp-content/uploads/2009/05/fix_eolas.js">fix_eolas</a>. El código es muy sencillo:</p>
<pre class="prettyprint">var objects = document.getElementsByTagName("object");

for (var i=0; i&lt;objects.length; i++)
	objects[i].outerHTML = objects[i].outerHTML;</pre>
<p>Lo que ese código hace es re-insertar todas las etiquetas &lt;object&gt;. Con eso es suficiente para eliminar el borde gris de activación.</p>
<p>Para recapitular, si ud. desea eliminar el borde gris solo tiene que hacer lo siguiente:</p>
<ol>
<li>Agregar la etiqueta a la cabecera.</li>
<li>Guardar el archivo <a href="http://jcesar.artelogico.com/wp-content/uploads/2009/05/fix_eolas.js">fix_eolas</a> junto con el HTML.</li>
<li>Asegurarse de que está probando desde un servidor web y no desde el disco duro.</li>
<li>???</li>
<li>¡Hacerse rico!</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://jcesar.artelogico.com/2009/05/eliminando-el-borde-gris-de-flash/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
