Foros del Web » Programando para Internet » PHP » Frameworks y PHP orientado a objetos »

MGTheme Class (clase para manejo de archivos template)

Estas en el tema de MGTheme Class (clase para manejo de archivos template) en el foro de Frameworks y PHP orientado a objetos en Foros del Web. Intro MGTheme es una clase para manejo de archivos template, esto permite separar el codigo de programacion php del de diseño (html/xml) , la utilizacion ...
  #1 (permalink)  
Antiguo 27/02/2006, 03:08
 
Fecha de Ingreso: febrero-2006
Mensajes: 4
Antigüedad: 18 años, 1 mes
Puntos: 0
MGTheme Class (clase para manejo de archivos template)

Intro

MGTheme es una clase para manejo de archivos template, esto permite separar el codigo de programacion php del de diseño (html/xml) , la utilizacion de esta clase es identica a la de la clase de TemplatePower o la utilizada por los foros phpBB, los que allan manejado alguna de estas, no tendran problema para entender el uso de MGTheme.

Nota: esto lo hize para facilitarme la mudanza de las aplicaciones que realize integradas con estas clases a mi clase.

Uso:

Asignacion de variables tpl
Esto asigna valor dinamico a un contenido variable en el tpl, el contenido variable es identificado por estar entre llaves ( {VAR} )

Ejemplo:

index.tpl
Código:
 
<html>
   <head>
	<title>{TITULO}</title>
   </head>
   <body>
		 Ejemplo MGTheme, desarrollado por <b> {AUTOR} </b>
   </body>
</html>
index.php
Código:
<?php
require_once("MGTheme.php"); // ( 1 )

$theme = new MGTheme("./"); // ( 2 )

$theme->Cargar(array(  // ( 3 )
   'index' => 'index.tpl')
);

$theme->AsignarVars(array(  // ( 4 )
	'TITULO' => 'Ejemplo clase MGTheme',
	'AUTOR' => 'Marioly')
);

$theme->Mostrar('index'); // ( 5 )

?>
1.- Incluimos el archivo php que contiene la clase
2.- Creamos un nuevo objeto de la clase, al constructor de clase pasamos un parametro que es el directorio donde estan los archivos tpl, en este caso trabajamos en el mismo directorio asi que sera "./" .
3.- Con el metodo Cargar asignamos el tpl que sera usado para esta iterasion, en este caso "index.tpl" y le asignamos un identificativo en el ejemplo es "index"
4.- Con AsignarVars asignamos valor a dos variables tpl con un array asociativo. Si se necesita asignar valor a solo una variable es posible usar el metodo AsignarVar donde el modo de uso es:
Código:
$theme->AsignarVar('NOMBRE_VAR', 'texto valor');
5.- Por ultimo utilizamos el metodo Mostrar para imprimir el resultado final del template, a este metodo se tiene que pasar por parametro el identificador del tpl requerido.

En este ejemplo el resultado seria una pagina html con titulo "Ejemplo clase MGTheme" y con contenido:
Cita:
Ejemplo MGTheme, desarrollado por Marioly
facil ha?

Uso de blockes
El uso de blockes es muy util, sobre todo usados en los bucles php. Ejemplo:

blockes.tpl
Código:
 
<html>
   <head>
	<title>{TITULO}</title>
   </head>
   <body>
		Ejemplo uso de blockes: <br />
		<!-- BEGIN blocke -->
		   Repeticion de blocke <b> {blocke.REPETICION} </b><br />
		<!-- END blocke -->
   </body>
</html>
blockes.php
Código:
<?php
require_once("MGTheme.php"); 

$theme = new MGTheme("./"); 

$theme->Cargar(array( // ( 1 )
   'blockes' => 'blockes.tpl')
);

$theme->AsignarVar('TITULO', 'Ejemplo blockes'); // ( 2 )

for($i=1;$i<=5;$i++) // ( 3 )
{
	 $theme->AsignarBlocke('blocke', array(
			  'REPETICION' => $i)
	);
}


$theme->Mostrar('blockes'); 

?>
1.- Como vimos en el ejemplo de arriba, tenemos que indicar el archivo que sera utilizado, con el metodo "Cargar".
2 . -Asignamos valor a la variable "TITULO", como es solo una variable usaremos el metodo AsignarVar
3 .-Creamos un bucle for de 5 repeticiones, dentro de este iniciamos un blocke tpl y asignamos valor a una variable de el con el metodo AsignarBlocke, como primer parametro de este, indicamos el nombre del blocke y como segundo un array asociativo con los valores de sus variables.En el template los blockes deben iniciarse de la forma:
Cita:
<!-- BEGIN nombre_blocke -->
y terminar:
Cita:
<!-- END nombre_blocke -->
y a sus variables debe anteponerse el nombre del blocke seguido de un punto:
Cita:
{nombre_blocke.VAR}
Si no se antepone el nombre del blocke, el trato a estas sera de variables normales, ya que dentro de los blockes pueden ser tmb introducidas variables normales.

El resultado del ejemplo seria:
Cita:
Ejemplo uso de blockes:
Repeticion de blocke 1
Repeticion de blocke 2
Repeticion de blocke 3
Repeticion de blocke 4
Repeticion de blocke 5
Uso de Sub-Blockes
Esto aunque algo complicado, tmb es muy util, y bueno tomando de ejemplo los bulletin boards, como habran notado la mayoria usan un bucle para mostrar las categorias y dentro de cada repeticion otro bucle para mostrar los foros de la categoria, esto seria imposible aderirlo a un tpl sin el uso de sub-blockes, Ejemplo:

sub_blockes.tpl
Código:
 
<html>
   <head>
   </head>
   <body>
		Ejemplo uso de Sub-blockes: <br />
		<!-- BEGIN blocke -->
		   Repeticion de blocke <b> {blocke.REPETICION} </b><br />
			  <!-- BEGIN sub_blocke -->
				  *Repeticion de Sub-blocke {blocke.sub_blocke.VARIABLE}
			  <!-- END sub_blocke -->
		<!-- END blocke -->
   </body>
</html>
sub_blockes.php
Código:
<?php
require_once("MGTheme.php"); 

$theme = new MGTheme("./"); 

$theme->Cargar(array( 
   'sub_blockes' => 'sub_blockes.tpl')
);

for($i=1;$i<=2;$i++) 
{
	 $theme->AsignarBlocke('blocke', array(
			  'REPETICION' => $i);
	);
		   for($m=1;$m<=2;$m++)
		  {
			  $theme->AsignarBlocke('blocke.sub_blocke', array(
					  'REPETICION' => $m);
			   );
		   }
}

$theme->Mostrar('sub_blockes'); 

?>
En este ejemplo, programamos un bucle de 2 repeticiones y dentro otro bucle de tmb 2 repeticiones, el primero asignara valor al blocke principal y el segundo al sublocke, por cada repeticion del blocke, el sublocke se repetira 2 veces, como pueden ver en el ejemplo, para indicar un sublocke se debe anteponer el nombre del blocke "padre" seguido de un [/b]. [/b](punto) del mismo modo las variables del sublocke deberan ser:
Cita:
{nombre_blocke.nombre_subblocke.VARIABLE}
El resultado de este ejemplo seria:
Cita:
Ejemplo uso de blockes:
Repeticion de blocke 1
Repeticion Sub-blocke 1
Repeticion Sub-blocke 2
Repeticion de blocke 2
Repeticion Sub-blocke 1
Repeticion Sub-blocke 2

Sin embargo, si programamos un sub-blocke dentro de otro:
Código:
require_once("MGTheme.php"); 

$theme = new MGTheme("./"); 

$theme->Cargar(array( 
   'sub_blockes' => 'sub_blockes.tpl')
);

for($i=1;$i<=2;$i++) 
{
	 $theme->AsignarBlocke('blocke1', array(
			  'REPETICION' => $i);
	);
		   for($m=1;$m<=2;$m++)
		  {
			  $theme->AsignarBlocke('blocke1.blocke2', array(
					  'REPETICION' => $m);
			   );

			   for($e=1;$e<=2;$e++)
			  {
				   $theme->AsignarBlocke('blocke2.blocke3', array(
							   'REPETICION' => $m);
					);
			   }
		   }
}

$theme->Mostrar('sub_blockes');
Como se esperaria, al asignar el tercer blocke, no es de la forma:
Cita:
blocke1.blocke2.blocke3
Sino que se toma solo el nombre del primer blocke superior, lo mismo pasa con las variables del tpl, esto lo hize por que me parecia engorroso poner tanto nombre de blocke =/ ,en la clase de phpBB o TemplatePower
si tienen que poner todos los blockes superiores.

Archivos Anidados
Los archivos anidados son archivos tpl, embebidos dentro de otros, por ejemplo, si tienes un header o un codigo html que quieres que aparesca en todas las paginass, puedes crear un tpl con ese codigo y aderirlo a las paginas, Ejemplo:

header.tpl
Código:
<b>MGTheme Class</b> by Marioly Garza

anidados.tpl
Código:
 
<html>
   <head>
   </head>
   <body>
		{HEADER} <br />
		Ejemplo uso de archivos anidados
   </body>
</html>
anidados.php
Código:
<?php
require_once("MGTheme.php"); 

$theme = new MGTheme("./"); 

$theme->Cargar(array( // ( 1 )
   'anidados' => 'anidados.tpl',
   'header' => 'header.tpl')
);

$theme->AsignarVarArc('HEADER' => 'header'); // (2)

$theme->Mostrar('anidados'); // (3)

?>
1 .- Cargamos los dos archivos tpl.Siempre se deben definir indicativos diferentes!
2.- Con el metodo AsignarVarArc asignamos el contenido del archivo a una variable, en este caso la variable "HEADER"
3.- Mostramos el resultado final, que seria:
Cita:
MGTheme Class by Marioly Garza
Ejemplo uso de archivos anidados
Por que el archivo "anidados.tpl" tiene dentro la variable "HEADER" la misma a la que asignamos el contenido de "header.tpl".

Con esto termino, espero sea entendible para todos, igual dudas, criticas, sugerencias, postean :D ,Thanks

Última edición por marioly; 13/04/2006 a las 15:09
  #2 (permalink)  
Antiguo 27/02/2006, 03:09
 
Fecha de Ingreso: febrero-2006
Mensajes: 4
Antigüedad: 18 años, 1 mes
Puntos: 0
MGTheme.php

Código:
<?php
/*
+----------------------------------------------------------------------
|		   Class MGTheme
|   ========================================
|   @developer  Marioly Garza
|   @copyright (C) 2005  MariolyGroup
|   @license GNU/GPL
|
|   ========================================
|   @Web hackyashira.com
|   @Email [email protected]
+-----------------------------------------------------------------------
|
|   > Clase para manejo de archivos template
|   + Manejo de variables
|   + Blockes
|   + Sub-Blockes
|   + Archivos anidados
|
+----------------------------------------------------------------------
*/

class MGTheme
{
   // Directorio de templates
   var $home = '';
   // Archivos template
   var $archivos = array();
   // Vars tpl
   var $datos_var = array();
   // Vars tpl de blocke
   var $datos_blk = array();
   // Archivos Asignados a parse
   var $datos_arc = array();
   
   
	/**
	* Class Constructor
	* Define el directorio principal de templates
	*
	* @param string $home directorio de templates
	* @access public
	*/
	function MGTheme($home = "./")
	{
	   if(!is_dir($home))
	   {
		 die('MGTheme: Error al abrir el directorio de templates.');
	   }
	   
	   $home = (substr($home, -1) != '/') ? $home . "/" : $home;

	   $this->home = $home;
	}
	
   /**
	* Asigna archivos template
	* 
	* @param array $archivos array asociativo de archivos
	* @access public
	*/
	function Cargar($archivos)
	{
		if (!is_array($archivos))
		{
			return false;
		}

		reset($archivos);
		while(list($nombre, $archivo) = each($archivos))
		{
			$this->archivos[$nombre] = $this->home . $archivo;
			if(!file_exists($this->archivos[$nombre]))
			{
			   die("MGTheme->Cargar(): El archivo " . $this->archivos[$nombre] . " no existe."); 
			}
		}

		return true;	   
	}
	
	/**
	* Imprime resultado final
	* 
	* @param string $archivo archivo a imprimir
	* @access public
	*/
	function Mostrar($archivo)
	{
		if (!$this->archivos[$archivo])
		{
			die("MGTheme->Mostrar(): No existe archivo asignado a " . $archivo);
		}
		//Verificar archivos asignados a parse
		$this->CheckAsignArc();
		
		//Mostrar resultado final
		print $this->Compilar($this->archivos[$archivo]);
	}
	
	/**
	* Asigna variable de archivo anidado.
	* 
	* @param string $var nombre variable
	* @param $archivo referencia de archivo
	* @access public
	*/
	function AsignarVarArc($var, $archivo)
	{
	   	if (!$this->archivos[$archivo])
		{
			die("MGTheme->AsignarVarArc(): No existe archivo asignado a " . $archivo);
		}
		
		$this->datos_arc[$var] = $archivo;
	
		return true;
	}
	
	/**
	* Asigna valor a variables tpl de blocke
	*
	* @param string $blocke nombre blocke
	* @param array $valores array asociativo de valores
	* @access public
	*/
	function AsignarBlocke($blocke, $valores)
	{
		
		if (strstr($blocke, '.'))
		{
			// Sub-Blocke
			$blockes = explode('.', $blocke);
			$blockcount = sizeof($blockes) - 1;
			$str = '$this->datos_blk';
			for ($i = 0; $i < $blockcount; $i++)
			{
				$str .= '[\'' . $blockes[$i] . '\']';
				eval('$lastiteration = sizeof(' . $str . ') - 1;');
				$str .= '[' . $lastiteration . ']';
			}
			$str .= '[\'' . $blockes[$blockcount] . '\'][] = $valores;';

			eval($str);
		}
		else
		{
			 //Blocke Normal
			 $this->datos_blk[$blocke][] = $valores;
		}
		 
		return true;
	}
 
	/*
	* Asigna valor a variables tpl 
	*
	* @param array $valores array asociativo de valores
	* @access public
	*/
	function AsignarVars($valores)
	{
		  reset($valores);
		  while(list($var, $valor) = each($valores))
		  {
			 $this->datos_var[$var] = $valor; 
		  }
		  
		  return true;
	}	

	/**
	* Asigna valor a solo una variable tpl
	*
	* @param string $var nombre var
	* @param string $valor valor var
	* @access public
	*/
	function AsignarVar($var, $valor)
	{
		$this->datos_var[$var] = $valor;
		
		return true;
	}
	
	/**
	* Verifica archivos asignados a parse
	*
	* @access public
	*/
	function CheckAsignArc()
	{
	   if(!empty($this->datos_arc))
	   {
		   while(list($var, $archivo) = each($this->datos_arc))
		   {
			  $data = '';
			  //Obtener contenido parseado del archivo
			  $data = $this->Compilar($this->archivos[$archivo]);
			  //Asignar el contenido a la variable especificada
			  $this->AsignarVar($var, $data);
		   }
	   }
	   
	   return true;
	}

	/**
	* Procesa el contenido del archivo cambiando variables tpl
	* por el valor programado y retorna resultado final
	*
	* @param string $archivo archivo a procesar
	* @access public
	*/
	function Compilar($archivo)
	{

		$cont = implode("", @file($archivo));
		if (empty($cont))
		{
			die('MGTheme->Compilar(): El archivo esta vacio.');
		}	
		
		if(!empty($this->datos_var))
		{
		  reset($this->datos_var);
		  while(list($var, $valor) = each($this->datos_var))
		  {
			 // Remplazar variables
			 $cont = str_replace("{" . $var . "}", preg_replace(array('/{/', '/}/'), array('&mgv;', '&mlv;'), $valor), $cont);
		  } 
		}
		  
		$final_blocke = array();
		
		if(!empty($this->datos_blk))
		{  
			reset($this->datos_blk);
			// Blockes			
			while(list($block) = each($this->datos_blk))
			{
				$final_blocke[$block] = $this->Blk($cont, $this->datos_blk, $block, '', false);
			   
				$cont = preg_replace("@<!--\s+BEGIN\s+" . $block . "\s+-->(.*?)<!--\s+END\s+" . $block . "\s+-->@sm", $final_blocke[$block], $cont);				  
			}
			
		} 
		  
		//Anular blockes no usados
		$cont = preg_replace('@<!--\s+BEGIN\s+([0-9A-Za-z_-]+)\s+-->(.*)<!--\s+END\s+\1\s+-->@sU', '', $cont);

		//Anular variables no usadas
		$cont = preg_replace('/{(.*?)}/', '', $cont);
		$cont = preg_replace(array('/&mgv;/i', '/&mlv;/i'), array('{', '}'), $cont);

		return $cont;		
	}

	/**
	* Metodo recursivo para blockes y sub-blockes 
	* lo que hace posible procesar arreglos tipo:
	* $this->datos_blk['parent'][]['$child'][]['$child2'][]...['$childN']
	*
	* @param string $texto texto a procesar
	* @param object $objeto objeto a desglosar
	* @param string $blocke nombre blocke
	* @param string $orig_blocke blocke padre (si existe)
	* @param bool $sub indicativo de sub-blocke
	* @access public
	*/
	function Blk($texto, $objeto, $blocke, $orig_blocke = '', $sub = false)
	{
		if(empty($blocke))
		{
		   return $texto;
		}
	   
		$texto_blk = '';
		
		// Contenido original de blocke
		if(preg_match("/<!-- BEGIN " . $blocke . " -->(.*?)<!-- END " . $blocke . " -->/sU", $texto, $text))
		{
			 $texto_blk = $text[1];
		}
					   
		$orig_blocke = ($sub == true) ? $orig_blocke . "." : "";
   			   
		$final_blocke = array();

		$contar = sizeof($objeto[$blocke]) - 1;
		
		// Definir remplazos
		for($i = 0; $i <= $contar; $i++)
		{
			$orig_blk = $repl_blk = $sublock = array();

			foreach($objeto[$blocke][$i] as $var => $valor)
			{
				 if(is_array($valor) && !in_array($var, $sublock) && !empty($var))
				 {
					$sublock[] = $var;
				 }
				 else
				 {
				   $orig_blk[] = "/{" . $orig_blocke . $blocke . "." . $var . "}/";
				   $repl_blk[] = preg_replace(array('/{/', '/}/'), array('&mgv;', '&mlv;'), $valor);
				 }
			}
			
			$texto_proc = $texto_blk;
			
			// Rutina de Sub-blockes (sino existe solo retornamos texto)
			$contar2 = sizeof($sublock) - 1;
			for($m = 0; $m <= $contar2; $m++)
			{
			  $texto_proc = $this->Blk($texto_proc, $objeto[$blocke][$i], $sublock[$m], $blocke, true);
			}
			
			// blocke final (vector)
			$final_blocke[$blocke] .= preg_replace($orig_blk, $repl_blk, ' ' . $texto_proc . ' ');
		}   
		// Si es Sub-blocke remplazamos contenido, sino solo devolvemos texto
		$texto = ($sub == true) ? preg_replace("@<!--\s+BEGIN\s+" . $blocke . "\s+-->(.*?)<!--\s+END\s+" . $blocke . "\s+-->@sU", $final_blocke[$blocke], $texto) : $final_blocke[$blocke];			  

		return $texto;
   }

}

?>
  #3 (permalink)  
Antiguo 27/02/2006, 07:44
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 2 meses
Puntos: 129
Gracías por el aporte.´

Ya que el código es extenso entre ejemplos y demás .. podrías dejar una referencia en las FAQ's de este subforo que apunte a este mensaje para que no quede en el olvido.

Un saludo,
  #4 (permalink)  
Antiguo 23/03/2006, 14:03
Avatar de keldrox  
Fecha de Ingreso: noviembre-2005
Mensajes: 95
Antigüedad: 18 años, 4 meses
Puntos: 2
Hola, toy siguiendo esta "guia" y he descubierto un pequeñisimo fallo. Pero bueno siempre es bueno saberlo es en el archivo blockes.php.

Código PHP:
<?php
require_once("MGTheme.php"); 

$theme = new MGTheme("./"); 

$theme->Cargar(array( // ( 1 )
   
'blockes' => 'blockes.tpl')
);

$theme->AsignarVar('TITULO''Ejemplo blockes'); // ( 2 )

for($i=1;$i<=5;$i++) // ( 3 )
{
     
$theme->AsignarBlocke('blocke', array(
              
'REPETICION' => $i);
    );
}


$theme->Mostrar('blockes'); 

?>
Código:
for($i=1;$i<=5;$i++) // ( 3 )
{
	 $theme->AsignarBlocke('blocke', array(
			  'REPETICION' => $i)
	);
}
Deveria ser asi sin ";" en el array.

Un saludo y muchas gracias por el codigo! aunque tengo unas cuantas dudas ...
  #5 (permalink)  
Antiguo 13/04/2006, 15:10
 
Fecha de Ingreso: febrero-2006
Mensajes: 4
Antigüedad: 18 años, 1 mes
Puntos: 0
Ou, error corregido =) gracias , sorry por dejar olvidado este mensaje y..., de las dudas, pues puedes postearlas, yo respondo con gusto :)
  #6 (permalink)  
Antiguo 28/04/2006, 03:12
 
Fecha de Ingreso: febrero-2004
Ubicación: Carthagena
Mensajes: 205
Antigüedad: 20 años, 1 mes
Puntos: 0
Buenas, aquí he puesto otro error que había en el ejemplo de Anidado.tpl:
http://foros.hackerss.com/index.php?...st=0#entry3359

Trascribo:

El ejemplo anidados.php me da error PHP (Parse error: parse error in ...\anidados.php on line 12)

Los ejemplos estan copiados literal de esta página y lo hice 2 veces desde 0, no sé si habrá algún error en la clase o en el ejemplo.

Parece ser que el problema está aqui:
Cita:
Iniciado por anidados.php
$theme->AsignarVarArc('HEADER' => 'header'); // (2)
que debería ser así:
Cita:
Iniciado por anidados.php
$theme->AsignarVarArc('HEADER', 'header'); // (2)
Reemplazando "=>" por "," (coma)
__________________
Retro Invaders : Mi blog

Última edición por josepzin; 28/04/2006 a las 09:55
  #7 (permalink)  
Antiguo 28/04/2006, 09:54
 
Fecha de Ingreso: febrero-2004
Ubicación: Carthagena
Mensajes: 205
Antigüedad: 20 años, 1 mes
Puntos: 0
Encontré otro posible error al hacer "blockes", trascribo desde el otro foro:http://foros.hackerss.com/index.php?...st=0#entry3419

De nuevo yo con otro posible error:

Es con el ejemplo: blockes.tpl
El error que da es: Notice: Undefined index: blocke in ...\MGTheme.php on line 330

En el servidor web no pone nada, pero en local (uso EasyPHP) me aparece ese mensaje. No sé si es algo grave o sólo es una advertencia sin importancia...
__________________
Retro Invaders : Mi blog
  #8 (permalink)  
Antiguo 28/04/2006, 15:58
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 2 meses
Puntos: 129
Cita:
Iniciado por josepzin
Encontré otro posible error al hacer "blockes", trascribo desde el otro foro:http://foros.hackerss.com/index.php?...st=0#entry3419

De nuevo yo con otro posible error:

Es con el ejemplo: blockes.tpl
El error que da es: Notice: Undefined index: blocke in ...\MGTheme.php on line 330

En el servidor web no pone nada, pero en local (uso EasyPHP) me aparece ese mensaje. No sé si es algo grave o sólo es una advertencia sin importancia...
Es una advertencia de que no se usó validaciones tipo "in_array()" .. o algún "isset()" para validar que el dato que va atacar a un indice de un array ($array[$indice]) exista.

El hecho de que veas ese "Notice" depende de la configuración de PHP sobre "error_display" y/o "error_reporting" (lo puedes ver en tu php.ini o phpinfo())

Un saludo,
__________________
Por motivos personales ya no puedo estar con Uds. Fue grato haber compartido todos estos años. Igualmente los seguiré leyendo.
  #9 (permalink)  
Antiguo 06/06/2006, 13:38
 
Fecha de Ingreso: febrero-2004
Ubicación: Carthagena
Mensajes: 205
Antigüedad: 20 años, 1 mes
Puntos: 0
Conocí esta Clase de Marioly en el foro de Hackerss, tenía tambien planteado varios de estos "problemas" y quedaron resueltos todos.

Ahora mismo estoy usando esta clase en varios proyectos y la verdad es que parece que funciona muy bien!!!! Alabad@ Marioly! :)
__________________
Retro Invaders : Mi blog
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 23:15.