<?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>mooontes.com &#187; montes</title>
	<atom:link href="http://mooontes.com/author/montes/feed/" rel="self" type="application/rss+xml" />
	<link>http://mooontes.com</link>
	<description></description>
	<lastBuildDate>Mon, 23 Jan 2012 18:15:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Nuestro repositorio Git remoto con Gitosis y Debian</title>
		<link>http://mooontes.com/2011/11/05/repositorio-git-remoto-gitosis-debian/</link>
		<comments>http://mooontes.com/2011/11/05/repositorio-git-remoto-gitosis-debian/#comments</comments>
		<pubDate>Sat, 05 Nov 2011 16:34:09 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[debian]]></category>
		<category><![CDATA[git gitosis linux mac osx debian remote repository]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=446</guid>
		<description><![CDATA[Para poder tener copias remotas de nuestros repositorios Git locales tenemos muchas opciones en internet, la más conocida de lejos github , que funciona muy bien para repositorios públicos y no excesivamente grandes, pero si necesitamos tener repositorios privados o de un tamaño considerable, las opciones tipo Github dejan de ser gratis. Podemos pagar uno [...]]]></description>
			<content:encoded><![CDATA[<p>Para poder tener copias remotas de nuestros repositorios Git locales tenemos muchas opciones en internet, la más conocida de lejos <a href="http://github.com">github</a> , que funciona muy bien para repositorios públicos y no excesivamente grandes, pero si necesitamos tener repositorios privados o de un tamaño considerable, las opciones tipo Github dejan de ser gratis.</p>
<p>Podemos pagar uno de estos servicios, pero si ya tenemos un servidor propio, ¿por qué no aprovecharlo también como repositorio remoto? Aquí es donde entra en juego &#8220;Gitosis&#8221;, que nos ayuda a mantener repositorios Git remotos en nuestro propio servidor, pudiendo configurar el acceso privado a los repositorios incluso por grupos.</p>
<h2>Instalar Gitosis en Debian</h2>
<p>Aunque hay varios tutoriales por internet e incluso un paquete en debian para instalar Gitosis, todos los métodos que he visto dan algún problema más o menos grave. Los siguientes pasos son producto de mezclar varios pasos de los descritos en estos tutoriales y de añadir alguno propio para lograr hacer funcionar correctamente Gitosis en un servidor debian.</p>
<ol>
<span id="more-446"></span></p>
<li>
<h3>Instalar python-setuptools y descargar Gitosis</h3>
</li>
<p>En el servidor:</p>
<pre class="brush: bash; title: ; notranslate">aptitude install python-setuptools</pre>
<p>y descargar Gitosis (clonar con Git)</p>
<pre class="brush: bash; title: ; notranslate">cd /data/temp
git clone git://eagain.net/gitosis</pre>
<p>(Gitosis también está disponible en github: <a href="https://github.com/res0nat0r/gitosis">https://github.com/res0nat0r/gitosis</a> )</p>
<li>
<h3>Instalar Gitosis</h3>
</li>
<p>Ojo con el parámetro &#8220;<em>&#8211;home /data/git</em>&#8220;, aquí deberéis indicar el home del usuario git, que es donde se almacenarán los repositorios</p>
<pre class="brush: bash; title: ; notranslate">python setup.py install
adduser --system --shell /bin/sh --gecos 'git version control' --group --disabled-password --home /data/git git</pre>
<li>
<h3>Generar una llave pública en nuestro ordenador local</h3>
</li>
<p>Tras instalar Gitosis en el servidor, ahora necesitaremos generar una llave pública en nuestro ordenador de desarrollo (desde donde vayamos a hacer los push)</p>
<p>En Linux o Mac:</p>
<pre class="brush: bash; title: ; notranslate">ssh-keygen -t rsa</pre>
<p>Lo que generará las llaves privada/pública en nuestro directorio de usuario, la que nos interesa, la pública, en: &#8220;<em>/home/usuario/.ssh/id_rsa.pub</em>&#8221; en Linux o &#8220;<em>/Users/usuario/.ssh/id_rsa.pub</em>&#8221; en OS X.</p>
<li>
<h3>Instalar nuestra llave pública en el servidor</h3>
</li>
<p>De vuelta al servidor y habiendo subido nuestra llave pública (por ftp por ejemplo)</p>
<p>Lo primero instalamos sudo, que en debian no viene instalado por defecto:</p>
<pre class="brush: bash; title: ; notranslate">aptitude install sudo</pre>
<p>Inicializamos Gitosis con nuestro usuario como admin (pasándole la ruta de nuestra llave pública, en este ejemplo estaría en &#8220;<em>/tmp/id_rsa.pub</em>&#8221;</p>
<pre class="brush: bash; title: ; notranslate">sudo -H -u git gitosis-init &lt; /tmp/id_rsa.pub</pre>
<p>Y para finalizar marcamos &#8220;post-update&#8221; como ejecutable para todos los usuarios:</p>
<pre class="brush: bash; title: ; notranslate">sudo chmod 755 /data/git/repositories/gitosis-admin.git/hooks/post-update</pre>
<li>
<h3>Bonus track: Redmine o cualquier gestor web de Git en el servidor</h3>
</li>
<p>Si vamos a usar Redmine o cualquier tipo de gestor o visualizador web de Git, necesitaremos incluir al usuario de apache &#8220;www-data&#8221; en el grupo de &#8220;git&#8221; para que sea capaz de leer los repositorios que generemos:</p>
<pre class="brush: bash; title: ; notranslate">usermod -a -G git www-data</pre>
<li>
<h3>Ya estamos listos, nuestro primer push</h3>
</li>
<p>Ya sólo nos queda clonar el repositorio de la configuración de Gitosis para poder ir configurando los permisos para los repositorios que añadamos, desde nuestro ordenador de desarrollo (Linux o Mac) sustituyendo &#8220;miservidor.com&#8221; por el dominio o ip de vuestro servidor:</p>
<pre class="brush: bash; title: ; notranslate">git clone git@miservidor.com:gitosis-admin.git</pre>
<p>y ahora podemos entrar a ver la configuración de gitosis y añadir algún repositorio, por ejemplo si queremos añadir el repositorio &#8220;montes&#8221; a nuestro servidor:</p>
<pre class="brush: bash; title: ; notranslate">cd gitosis-admin
vim gitosis.conf</pre>
<p>y en &#8220;<em>gitosis.conf</em>&#8221; añadiremos &#8220;montes&#8221; como writable:</p>
<pre class="brush: bash; title: ; notranslate">[gitosis]
  3 [group gitosis-admin]
  4 writable = gitosis-admin montes
  5 members = yo@gmail.com
</pre>
<p>grabamos y haremos nuestro primer push para actualizar la configuración de gitosis en el servidor remoto:</p>
<pre class="brush: bash; title: ; notranslate">git commit -a -m &quot;Dar permisos de escritura en el repositorio montes para el grupo gitosis-admin&quot;
git push</pre>
<p>Con esto hemos dado permisos de escritura en el repositorio &#8220;montes&#8221; (que aún no existe) a nuestro usuario (yo@gmai.com al que pertenece la llave pública que configuramos en el paso anterior).</p>
<p>Sólo nos queda crear el repositorio en nuestro ordenador de desarrollo (Linux o Mac):</p>
<pre class="brush: bash; title: ; notranslate">cd ..
mkdir montes
cd montes
git init</pre>
<p>añadir nuestro servidor remoto como repositorio remoto:</p>
<pre class="brush: bash; title: ; notranslate">git remote add origin git@miservidor.com:montes</pre>
<p>y hacer nuestro primer push!</p>
<pre class="brush: bash; title: ; notranslate">git add .
git commit -a -m &quot;Primer commit!&quot;
git push miservidor master</pre>
<p>Listo! ya hemos enviado nuestro primer push a nuestro propio servidor Git remoto!</p>
</ol>
<p>&nbsp;</p>
<p>Fuentes:<br />
<a href="http://ymbra.com/es/blog/ramon/gestion-de-repositorios-git-con-gitosis">http://ymbra.com/es/blog/ramon/gestion-de-repositorios-git-con-gitosis</a><br />
<a href="https://github.com/res0nat0r/gitosis">https://github.com/res0nat0r/gitosis</a></p>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2011/11/05/repositorio-git-remoto-gitosis-debian/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Conferencia PHP Profesional &#8211; Carlos Buenosvinos</title>
		<link>http://mooontes.com/2011/05/23/conferencia-php-profesional-carlos-buenosvinos/</link>
		<comments>http://mooontes.com/2011/05/23/conferencia-php-profesional-carlos-buenosvinos/#comments</comments>
		<pubDate>Mon, 23 May 2011 22:42:14 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[programacion]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=432</guid>
		<description><![CDATA[Si te interesa PHP, te recomiendo que busques como sea un par de horas libres y te veas la conferencia de Carlos Buenosvinos sobre las herramientas necesarias para programar en PHP profesionalmente, vale su peso en oro (y gracias de nuevo a decharlas.com!) Vídeo Vimeo Conferencia PHP Profesional y diapositivas]]></description>
			<content:encoded><![CDATA[<p>Si te interesa PHP, te recomiendo que busques como sea un par de horas libres y te veas la conferencia de Carlos Buenosvinos sobre las herramientas necesarias para programar en PHP profesionalmente, vale su peso en oro (y gracias de nuevo a <a href='http://www.decharlas.com'>decharlas.com</a>!)</p>
<p><a target='_blank' href='http://decharlas.uji.es/php-profesional.php'>Vídeo Vimeo Conferencia PHP Profesional y diapositivas</a></p>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2011/05/23/conferencia-php-profesional-carlos-buenosvinos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2, tutorial para comenzar ultra-rápido</title>
		<link>http://mooontes.com/2011/03/27/symfony2-tutorial-para-comenzar-ultra-rapido/</link>
		<comments>http://mooontes.com/2011/03/27/symfony2-tutorial-para-comenzar-ultra-rapido/#comments</comments>
		<pubDate>Sun, 27 Mar 2011 01:32:44 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[programacion]]></category>
		<category><![CDATA[symfony2]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=380</guid>
		<description><![CDATA[This post in english at http://en.mooontes.com/2011/03/27/symfony2-ultra-fast-start-tutorial/ NOTA: Este tutorial se ha realizado en Ubuntu 11.04 &#8211; Natty Narwhal, no se ha comprobado su funcionamiento en otros sistemas operativos. Esto es sólo una especie de chuleta de ejemplo por si se te olvida alguna cosa tras leer la documentación de symfony2, pero evidentemente es imprescindible leérsela [...]]]></description>
			<content:encoded><![CDATA[<p><em>This post in english at <a href="http://en.mooontes.com/2011/03/27/symfony2-ultra-fast-start-tutorial/">http://en.mooontes.com/2011/03/27/symfony2-ultra-fast-start-tutorial/</a></p>
<p>NOTA: Este tutorial se ha realizado en Ubuntu 11.04 &#8211; Natty Narwhal, no se ha comprobado su funcionamiento en otros sistemas operativos. Esto es sólo una especie de chuleta de ejemplo por si se te olvida alguna cosa tras leer la documentación de symfony2, pero evidentemente es imprescindible leérsela antes para saber de qué va todo esto <img src='http://mooontes.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  <a href="http://symfony.com/doc/2.0/book/index.html">http://symfony.com/doc/2.0/book/index.html</a></em></p>
<p>El código fuente utilizado está disponible en: <a href='https://github.com/montes/Adictos-Symfony2-Bundle' target='_blank'>https://github.com/montes/Adictos-Symfony2-Bundle</a></p>
<p>ACTUALIZACIÓN 23/5/2011: Actualizado para symfony2 beta2</p>
<p>&nbsp;</p>
<h2>1. Descarga</h2>
<p>Descarga Symfony2 Standard Edition (en el momento de escribir esto la BETA2): <a href='http://symfony.com/download' target='_blank'>http://symfony.com/download</a></p>
<p>Descomprime</p>
<pre class="brush: bash; title: ; notranslate">
tar -zxvf Symfony_Standard_Vendors_2.0.0BETA2.tgz
</pre>
<p>Y cambia los permisos de app/cache y app/logs para que sean escribibles por php, por ejemplo:</p>
<pre class="brush: bash; title: ; notranslate">
chmod 777 app/cache app/logs
</pre>
<p>Configura en tu servidor el directorio &#8220;<em>web/</em>&#8221; como raíz y ya deberías poder cargar la página de bienvenida de symfony2 desde <a target="_blank"  href="http://127.0.0.1/app_dev.php/">http://127.0.0.1/app_dev.php/</a></p>
<p><span id="more-380"></span></p>
<p>&nbsp;</p>
<h2>2. Configura la base de datos</h2>
<p>Configura <em>app/config/parameters.ini</em> con las opciones de tu base de datos (también lo puedes hacer desde <a href="http://127.0.0.1/app_dev.php/_configurator/">http://127.0.0.1/app_dev.php/_configurator/</a> ), para mysql sería algo así:</p>
<pre class="brush: plain; title: ; notranslate">
[parameters]
    database_driver=pdo_mysql
    database_host=localhost
    database_name=symfony2
    database_user=symfony2
    database_password=password
    mailer_transport=smtp
    mailer_host=localhost
    mailer_user=
    mailer_password=
    locale=en
    csrf_secret=op234j234j2424jojpfwesdcsdc
</pre>
<p>&nbsp;</p>
<h2>3. Crear nuestro primer bundle</h2>
<p>Ahora ya podemos crear un bundle:</p>
<pre class="brush: bash; title: ; notranslate">
php app/console init:bundle &quot;Montes\AdictosBundle&quot; src
</pre>
<p>Ahora toca añadir a <em>app/autoload.php</em> :</p>
<pre class="brush: php; title: ; notranslate">
$loader-&gt;registerNamespaces(array(
    'Montes'                         =&gt; __DIR__.'/../src',
    // ...
));
</pre>
<p>y añadir a <em>app/AppKernel.php</em> :</p>
<pre class="brush: php; title: ; notranslate">
    $bundles = array(
        // ...
        new Montes\AdictosBundle\MontesAdictosBundle(),
    );
</pre>
<p>&nbsp;</p>
<h2>4. Ruta</h2>
<p>Para que symfony2 sepa dónde enviar las peticiones, añadimos a <em>app/config/routing_dev.yml</em> :</p>
<pre class="brush: bash; title: ; notranslate">
homepage:
    pattern:  /adictos
    defaults: { _controller: MontesAdictosBundle:Default:index }
</pre>
<p>En este punto ya podemos cargar nuestro recién creado bundle yendo a: <a target="_blank" href="http://127.0.0.1/app_dev.php/adictos">http://127.0.0.1/app_dev.php/adictos</a></p>
<p>&nbsp;</p>
<h2>5. Controller</h2>
<p>El controller por defecto (<em>Montes/AdictosBundle/Controller/DefaultController.php</em>) ya nos lo ha creado Symfony2, ahora vamos a crear el controller StoreController.php</p>
<pre class="brush: php; title: ; notranslate">
//Montes/AdictosBundle/Controller/StoreController.php
&lt;?php

namespace Montes\AdictosBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class StoreController extends Controller
{
    /**
     * @Template()
     */
    public function indexAction($store)
    {
        return array('store' =&gt; $store);
    }
}
</pre>
<p>y añadimos a <em>app/config/routing_dev.yml</em></p>
<pre class="brush: bash; title: ; notranslate">
store:
    pattern: /adictos/{store}
    defaults: { _controller: MontesAdictosBundle:Store:index }
</pre>
<p>y una nueva plantilla de twig a <em>Montes/AdictosBundle/Resources/Views/Store/index.html.twig</em></p>
<pre class="brush: xml; title: ; notranslate">
So you want store &quot;{{ store }}&quot;?
</pre>
<p>Y ahora cargando <a target="_blank" href="http://127.0.0.1/app_dev.php/adictos/mi-tienda">http://127.0.0.1/app_dev.php/adictos/mi-tienda</a> obtendremos:</p>
<p><em>So you want store &#8220;mi-tienda&#8221;?</em></p>
<p>&nbsp;</p>
<h2>6. Modelo</h2>
<p><em>NOTA: Para entrar en detalle sobre Doctrine2 recomiendo <a target='_blank' href='http://parasitovirtual.wordpress.com/category/cursos-y-articulos/desarrollo-de-webs/php/doctrine/'>el blog de Francisco Belmonte</a>, una maravilla.</em></p>
<p><del datetime="2011-05-23T21:32:54+00:00">Primero añadimos a <em>app/config/config.yml</em> &#8220;<em>MontesAdictosBundle: ~</em>&#8220;</del> A partir de la BETA1 por defecto el mapping es automático.</p>
<p>Comenzamos con Doctrine, vamos a definir nuestro modelo para una tienda. Antes de nada, como aún no hemos creado ningún modelo tendremos que crear el directorio <em>Montes/AdictosBundle/Entity</em> que es donde los guardaremos todos.</p>
<p>Y ya podemos empezar, modelo para Store:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
// Montes/AdictosBundle/Entity/Store.php

namespace Montes\AdictosBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Store
{
    /**
     * @ORM\Id
     * @ORM\Column(type=&quot;integer&quot;)
     * @ORM\GeneratedValue(strategy=&quot;AUTO&quot;)
     */
     protected $id;

    /**
     * @ORM\ManyToMany(targetEntity=&quot;Category&quot;)
     * @ORM\JoinTable(name=&quot;stores_categories&quot;,
     *      joinColumns={@ORM\JoinColumn(name=&quot;store_id&quot;, referencedColumnName=&quot;id&quot;)},
     *      inverseJoinColumns={@ORM\JoinColumn(name=&quot;category_id&quot;, referencedColumnName=&quot;id&quot;)})
     */
    protected $categories;

    /**
     * @ORM\Column(type=&quot;string&quot;, length=&quot;255&quot;)
     */
    protected $url;

    /**
     * @ORM\Column(type=&quot;string&quot;, length=&quot;255&quot;)
     */
    protected $name;

    /**
     * @ORM\Column(type=&quot;integer&quot;)
     */
    protected $clicks = 0;

    /**
     * @ORM\Column(type=&quot;boolean&quot;)
     */
    protected $validated = false;

    /**
     * @ORM\Column(type=&quot;integer&quot;)
     */
    protected $pcomments = 0;

    /**
     * @ORM\Column(type=&quot;integer&quot;)
     */
    protected $ncomments = 0;

    /**
     * @ORM\Column(type=&quot;boolean&quot;)
     */
    protected $active = false;

    /**
     * @ORM\Column(type=&quot;datetime&quot;, name=&quot;updated_at&quot;)
     */
    protected $updatedAt;

    /**
     * @ORM\Column(type=&quot;datetime&quot;, name=&quot;created_at&quot;)
     */
    protected $createdAt;

    public function __construct()
    {
        $this-&gt;categories = new \Doctrine\Common\Collections\ArrayCollection();
        $this-&gt;createdAt = new \DateTime();
        $this-&gt;updatedAt = new \DateTime();
    }
}
</pre>
<p>Modelo para Category:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
// Montes/AdictosBundle/Entity/Category.php

namespace Montes\AdictosBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Category
{
    /**
     * @ORM\Id
     * @ORM\Column(type=&quot;integer&quot;)
     * @ORM\GeneratedValue(strategy=&quot;AUTO&quot;)
     */
    protected $id;

    /**
     * @ORM\OneToMany(targetEntity=&quot;Category&quot;, mappedBy=&quot;parent&quot;)
     */
    protected $children;

    /**
     * @ORM\ManyToOne(targetEntity=&quot;Category&quot;, inversedBy=&quot;children&quot;)
     * @ORM\JoinColumn(name=&quot;parent_id&quot;, referencedColumnName=&quot;id&quot;)
     * @ORM\Column(nullable=&quot;true&quot;)
     */
    protected $parent;

    /**
     * @ORM\ManyToMany(targetEntity=&quot;Store&quot;, mappedBy=&quot;categories&quot;)
     */
    protected $stores;

    /**
     * @ORM\Column(type=&quot;string&quot;, length=&quot;255&quot;)
     */
    protected $name;

    /**
     * @ORM\Column(type=&quot;string&quot;, length=&quot;255&quot;, name=&quot;url_string&quot;, unique=&quot;true&quot;)
     */
    protected $urlString;

    public function __construct()
    {
        $this-&gt;stores = new \Doctrine\Commmon\Collections\ArrayCollection();
    }
}
</pre>
<p>Y ahora vamos a consola y para generar las tablas en la base de datos ejecutamos:</p>
<pre class="brush: bash; title: ; notranslate">
php app/console doctrine:schema:create
</pre>
<p>y para completar nuestro modelo con sus getters/setters:</p>
<pre class="brush: bash; title: ; notranslate">
php app/console doctrine:generate:entities MontesAdictosBundle
</pre>
<p>&nbsp;</p>
<h2>7. Probando el modelo</h2>
<p>Vamos a cambiar la acción que muestra la tienda a su propia acción (storeAction) para hacer hueco al índice del store controller en indexAction, que ahora mostrará el total de tiendas que tenemos almacenadas en la BD.</p>
<pre class="brush: bash; title: ; notranslate">
# app/config/routing_dev.yml
store:
    pattern: /adictos/{store}
    defaults: { _controller: MontesAdictosBundle:Store:store }

store_index:
    pattern: /adictos/
    defaults: { _controller: MontesAdictosBundle:Store:index }
</pre>
<pre class="brush: php; title: ; notranslate">
&lt;?php
// Montes/AdictosBundle/Controller/StoreController.php

namespace Montes\AdictosBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class StoreController extends Controller
{

    /**
     * @Template()
     */
    public function indexAction()
    {
        $em = $this-&gt;get('doctrine.orm.entity_manager');
        $stores = $em-&gt;createQuery('SELECT count(s.id) AS total FROM Montes\AdictosBundle\Entity\Store s')-&gt;getSingleScalarResult();
        return array('stores' =&gt; $stores);
    }

    /**
     * @Template()
     */
    public function storeAction($store)
    {
        return array('store' =&gt; $store);
    }
}
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;!-- Montes/AdictosBundle/Resources/views/Store/index.html.twig --&gt;
We have a total of {{ stores }} stores.
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;!-- Montes/AdictosBundle/Resources/views/Store/store.html.twig --&gt;
So you want store &quot;{{ store }}&quot;?
</pre>
<p>Ahora al cargar <a target="_blank" href="http://127.0.0.1/app_dev.php/adictos/">http://127.0.0.1/app_dev.php/adictos/</a> nos saldrá <em>We have a total of 0 stores</em> y al cargar <a target="_blank" href="http://127.0.0.1/app_dev.php/adictos/mi-tienda">http://127.0.0.1/app_dev.php/adictos/mi-tienda</a> nos saldrá <em>So you want store &#8220;mi-tienda&#8221;?</em><br />
<a href="http://github.com/montes/Adictos-Symfony2-Bundle"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://d3nwyuy0nl342s.cloudfront.net/img/e6bef7a091f5f3138b8cd40bc3e114258dd68ddf/687474703a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67" alt="Fork me on GitHub"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2011/03/27/symfony2-tutorial-para-comenzar-ultra-rapido/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>USB TDT (DVB-T) HD para Ubuntu, OSX y Windows</title>
		<link>http://mooontes.com/2010/11/29/usb-tdt-dvb-t-hd-para-ubuntu-osx-y-windows/</link>
		<comments>http://mooontes.com/2010/11/29/usb-tdt-dvb-t-hd-para-ubuntu-osx-y-windows/#comments</comments>
		<pubDate>Mon, 29 Nov 2010 18:32:53 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[Hardware]]></category>
		<category><![CDATA[dvb-t]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[tdt]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[usb]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=365</guid>
		<description><![CDATA[Llevaba tiempo buscando una tarjeta o USB TDT HD que fuese compatible con los tres sistemas operativos que utilizo y al final lo he encontrado, es el WinTV NOVA-T-HD: Funciona tanto en Ubuntu 10.10 como OSX 10.6.5 sólo conectándolo, no hay que configurar nada. En el caso de Windows aún no he probado, pero trae [...]]]></description>
			<content:encoded><![CDATA[<p>Llevaba tiempo buscando una tarjeta o USB TDT HD que fuese compatible con los tres sistemas operativos que utilizo y al final lo he encontrado, es el WinTV NOVA-T-HD:<br />
<a href="http://www.hauppauge.es/site/products/data_novathdstick.html"><img src="http://mooontes.com/wp-content/uploads/2010/11/novathdstick_top-300x96.jpg" alt="wintv nova-tdt-hd" title="wintv nova-tdt-hd" width="450" class="alignnone size-medium wp-image-367" /></a></p>
<p>Funciona tanto en Ubuntu 10.10 como OSX 10.6.5 sólo conectándolo, no hay que configurar nada. En el caso de Windows aún no he probado, pero trae un CD con los drivers.</p>
<p>En Ubuntu 10.10 yo lo uso con Me TV (<em>sudo aptitude install me-tv</em>)</p>
<p><img src="http://mooontes.com/wp-content/uploads/2010/11/me-tv.png" alt="" title="me-tv" width="567" height="419" class="alignnone size-full wp-image-373" /></p>
<p>En OSX sólo hay que instalar <a href='http://www.elgato.com/elgato/int/mainmenu/products/software/EyeTV-3/product1.en.html'>Eye TV</a> y funcionará perfectamente, ya que este USB es el que llevan dentro los famosos USB de &#8220;elgato&#8221; para Mac.</p>
<p>Yo la compré en un MediaMarkt, creo recordar que por algo menos de 50€ pero se encuentra fácil por internet, por ejemplo en <a href='http://www.pixmania.com/es/es/4031007/art/hauppauge/memoria-usb-wintv-nova-t.html'>pixmania</a>.</p>
<p>- Review en castellano: <a href='http://www.mashardware.com/index.php?/Articulos/Review-de-la-sintonizadora-Hauppauge-WinTV-NOVA-T-HD.html'>mashardware.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2010/11/29/usb-tdt-dvb-t-hd-para-ubuntu-osx-y-windows/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>VPN SSL de Juniper Networks en Debian sin entorno gráfico</title>
		<link>http://mooontes.com/2010/09/06/vpn-ssl-de-juniper-networks-en-debian-sin-entorno-grafico/</link>
		<comments>http://mooontes.com/2010/09/06/vpn-ssl-de-juniper-networks-en-debian-sin-entorno-grafico/#comments</comments>
		<pubDate>Mon, 06 Sep 2010 13:36:40 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[debian]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[juniper]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=347</guid>
		<description><![CDATA[Esta semana he tenido que cambiar el acceso a VPN desde nuestro servidor Debian, que hasta ahora era transparente (mediante Cisco) a una VPN SSL de Juniper Networks, ha llevado bastante tiempo y pruebas sobre todo debido a que no hay soporte de Debian por parte de Juniper, sólo para Red Hat y al final [...]]]></description>
			<content:encoded><![CDATA[<p>Esta semana he tenido que cambiar el acceso a VPN desde nuestro servidor Debian, que hasta ahora era transparente (mediante Cisco) a una VPN SSL de Juniper Networks, ha llevado bastante tiempo y pruebas sobre todo debido a que no hay soporte de Debian por parte de Juniper, sólo para Red Hat y al final se trata de prueba/error.</p>
<p>Nuestro servidor es un Debian Lenny sin entorno gráfico, ese fue uno de los primeros problemas ya que las soluciones que existen por internet y el propio cliente de Juniper para Linux, están siempre pensados para clientes con entorno gráfico.</p>
<p><span id="more-347"></span></p>
<p>&nbsp;</p>
<h2>1. Pasos previos</h2>
<p>Antes de comenzar con la configuración en el servidor, a través de un pc con Linux con entorno gráfico (y java instalado) obtendremos los ficheros necesarios.<br />
Sólo tenemos que conectar a la web de la VPN (yo utilicé Ubuntu+Firefox), con esto nos descargará a <em>/home/user/.juniper_networks/</em> todos los archivos necesarios para la conexión, no importa si establece la conexión a la VPN o no.</p>
<p>Desde <em>/home/usuario/</em> realizamos:</p>
<pre class="brush: bash; title: ; notranslate">tar -czvf juniper.tgz .juniper_networks/*</pre>
<p>Y ya hemos terminado con el pc y podemos pasar al servidor.</p>
<p>&nbsp;</p>
<h2>2. Preparación de archivos para la conexión</h2>
<p>Descomprimimos <em>juniper.tgz</em> en el servidor en <em>/home/usuario/.juniper_networks/</em> y descomprimimos el archivo <em>/home/usuario/.juniper_networks/ncLinuxApp.jar</em></p>
<pre class="brush: bash; title: ; notranslate">jar -xf ncLinuxApp.jar</pre>
<p>Con esto obtenemos varios archivos importantes:</p>
<ol>
<li><strong>getx509certificate.sh</strong> Necesario para obtener el certificado del servidor</li>
<li><strong>ncsvc</strong> El servicio que crea la conexión VPN</li>
</ol>
<p>&nbsp;</p>
<h2>3. Obtener el certificado</h2>
<p>Desde el mismo directorio:</p>
<pre class="brush: bash; title: ; notranslate">chmod +x getx509certificate.sh
./getx509certificate.sh vpn.empresa.com vpn.crt</pre>
<p>Con esto ya tenemos uno de los archivos necesarios para establecer la VPN, el <em>vpn.crt</em></p>
<p>&nbsp;</p>
<h2>4. Instalar el servicio</h2>
<p>Ejecutar como root:</p>
<pre class="brush: bash; title: ; notranslate">install -m 6711 -o root /home/usuario/.juniper_networks/ncsvc /home/usuario/.juniper_networks/network_connect/ncsvc</pre>
<p>&nbsp;</p>
<h2>5. Establecer la conexión</h2>
<p>Ya sólo queda establecer la conexión, para esto necesitaremos consultar al administrador el parámetro &#8220;realm&#8221;, por internet comentan que suele estar entre el HTML de la página de acceso, pero en mi caso no era así.</p>
<p>Conociendo este parámetro sólo nos falta realizar la conexión propiamente dicha:</p>
<pre class="brush: bash; title: ; notranslate">./ncsvc -h vpn.empresa.com -u user01 -p password -r realm -f vpn.crt</pre>
<p>Si en nuestro caso la VPN utiliza URIs personalizadas es necesario añadir también el parámetro <em>-U</em></p>
<pre class="brush: bash; title: ; notranslate">./ncsvc -h vpn.empresa.com -u user01 -p password -r realm -f vpn.crt -U https://vpn.empresa.com/aux/usuario01/</pre>
<p>Entonces el terminal quedará con el mensaje:</p>
<pre class="brush: bash; title: ; notranslate">Connecting to vpn.empresa.com : 443</pre>
<p>Y la VPN conectada hasta que caduque la sesión o cancelemos. La conexión creará un nuevo interface de red <em>tun0</em> (lo podréis ver con <em>ifconfig</em>) y añadirá también unas rutas (ver con <em>route</em>) y unas líneas a <em>/etc/resolv.conf</em></p>
<p>Si de esta forma no funciona y los parámetros son correctos, antes de realizar más pruebas debemos contactar con el administrador, puesto que en algunos casos, como por ejemplo que esté configurado para múltiples sesiones, no funcionará.</p>
<p>&nbsp;</p>
<p><strong>Más documentación:</strong></p>
<ul>
<li><a href="http://www.emiliojuarez.es/Utilidades/juniperendebianlenny.html">emiliojuarez.es</a></li>
<li><a href="http://www.entropy.ch/blog/Mac+OS+X/?permalink=Juniper-Network-Connect-SSL-VPN-and-Virtualization.html">entropy.ch</a></li>
<li><a href="http://mad-scientist.us/juniper.html">mad-scientist.us</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2010/09/06/vpn-ssl-de-juniper-networks-en-debian-sin-entorno-grafico/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Free Javascript Calendar / Datepicker adaptado a España</title>
		<link>http://mooontes.com/2010/03/07/javascript-calendar-datepicker/</link>
		<comments>http://mooontes.com/2010/03/07/javascript-calendar-datepicker/#comments</comments>
		<pubDate>Sun, 07 Mar 2010 17:10:42 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[programacion]]></category>
		<category><![CDATA[calendar]]></category>
		<category><![CDATA[datepicker]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=339</guid>
		<description><![CDATA[Necesitaba un calendario en javascript tipo pop-up para el proyecto que tengo entre manos y me he encontrado con Javascript Calendar que tiene muy buena pinta, pero que sólo tiene versión anglosajona así que lo he modificado para adaptarlo a mis necesidades: Días de la semana y meses en castellano Primer día de la semana [...]]]></description>
			<content:encoded><![CDATA[<p>Necesitaba un calendario en javascript tipo pop-up para el proyecto que tengo entre manos y me he encontrado con <a href="http://javascriptcalendar.org">Javascript Calendar</a> que tiene muy buena pinta, pero que sólo tiene versión anglosajona así que lo he modificado para adaptarlo a mis necesidades:</p>
<ol>
<li>Días de la semana y meses en castellano</li>
<li>Primer día de la semana Lunes</li>
<li>Formato de fecha dd-mm-yyyy</li>
<li>Posibilidad de darle un id al node (span) que crea</li>
<li>Posiblidad de pasarle el path de las imágenes por si queremos que sea distinto al original</li>
</ol>
<p>Para usar la versión modificada, debéis descargar primero la original de su página y luego sobreescribir &#8220;<em>jsDatePick.full.1.0.js</em>&#8221; con el modificado &#8220;<em>jsDatePick.full.1.0.spain.js</em>&#8221; <a href="http://mooontes.com/codigo/jsDatePick.full.1.0.spain.js">Javascript Calendar Spanish Version</a></p>
<p>Este sería un ejemplo de uso con las dos nuevas opciones (<em>id</em> y <em>path</em>):</p>
<pre lang='javascript'>		new JsDatePick({
			useMode:2,
			id:"idCalendarNode",
			path:"/mis-imagenes/",
			target:"beginDate"
		});
</pre>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2010/03/07/javascript-calendar-datepicker/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Maps API V3 get_center ahora es getCenter</title>
		<link>http://mooontes.com/2010/02/04/google-maps-api-v3-get_center-ahora-es-getcenter/</link>
		<comments>http://mooontes.com/2010/02/04/google-maps-api-v3-get_center-ahora-es-getcenter/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 17:43:36 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=333</guid>
		<description><![CDATA[He actualizado los ejemplos de Google Maps API V3 que habían dejado de funcionar debido a un cambio en el nombre de la función get_center que ha pasado a ser getCenter. También he eliminado la librería scrollwheelzoom que ya no es necesaria.]]></description>
			<content:encoded><![CDATA[<p>He actualizado los ejemplos de Google Maps API V3 que habían dejado de funcionar debido a un cambio en el nombre de la función <em>get_center</em> que ha pasado a ser <em>getCenter</em>.</p>
<p>También he eliminado la librería scrollwheelzoom que ya no es necesaria.</p>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2010/02/04/google-maps-api-v3-get_center-ahora-es-getcenter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Maps API V3 (javascript)</title>
		<link>http://mooontes.com/2009/07/30/google-maps-api-v3-javascript-2/</link>
		<comments>http://mooontes.com/2009/07/30/google-maps-api-v3-javascript-2/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 19:14:21 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[programacion]]></category>
		<category><![CDATA[api v3]]></category>
		<category><![CDATA[google maps]]></category>
		<category><![CDATA[google maps api v3]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[reverse geocoding]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=319</guid>
		<description><![CDATA[Versión en español de este post Although the Google Maps API V3 is still quite green and much remains to be polished, it is quite usable and if you only need the basic features of Google Maps, then you can use it for your project, the new speed and usability at portable devices is a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://mooontes.com/2009/07/29/google-maps-api-v3-javascript/">Versión en español de este post</a></p>
<p>Although the Google Maps API V3 is still quite green and much remains to be polished, it is quite usable and if you only need the basic features of Google Maps, then you can use it for your project, the new speed and usability at portable devices is a plus.</p>
<p>This code is an example of the use of various techniques with javascript:</p>
<ul>
<li>Map centering at user&#8217;s location</li>
<li>Event capturing</li>
<li>Reverse Geocoding</li>
<li>Use of <a href="http://google-maps-utility-library-v3.googlecode.com/svn/tags/scrollwheelzoom/1.0/docs/examples.html">Nianwei&#8217;s library</a> scrollwheelzoom (still not officially supported in V3)</li>
</ul>
<p><span id="more-319"></span></p>
<h3 style="clear:both;padding:20px;width:200px;text-align:center;margin:0px auto;"><a href="http://mooontes.com/codigo/google_maps_api_v3_en.html" target="_blank">Test the code</a></h3>
<p>And here is the code (<a href="http://validator.w3.org/check?uri=http://mooontes.com/codigo/google_maps_api_v3_en.html">validated</a> XHTML with Doctype).</p>
<pre class="brush: xml; title: ; notranslate">
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;!--
** Created at 2009 July by Montes http://mooontes.com
** Under licence http://creativecommons.org/licenses/by/3.0/es/deed.es
**
** Google Maps API V3 javascript example
**
** Visitor's location map centering, event capturing,
** reverse geocoding &amp; Nianwei's scrollwheelzoom
**
**
** Creado en Julio de 2009 por Montes http://mooontes.com
** Bajo licencia http://creativecommons.org/licenses/by/3.0/es/deed.es
**
** Ejemplo de programación con Google Maps API V3
**
** Centrado del mapa en la ubicación del visitante, captura de eventos,
** reverse geocoding y uso de la libreria para hacer zoom con la rueda del ratón
--&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;es&quot; lang=&quot;es&quot;&gt;
&lt;head&gt;

	&lt;meta name=&quot;viewport&quot; content=&quot;initial-scale=1.0, user-scalable=no&quot; /&gt;
	&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;

	&lt;title&gt;Test Google Maps API V3 -mooontes.com-&lt;/title&gt;

    &lt;style type=&quot;text/css&quot;&gt;
	html
	{
		border:0;
		padding:0;
		margin:0;
		width:100%;
		height:100%;
	}
	body
	{
		border:0;
		padding:0;
		margin:0;
		width:100%;
		height:100%;
	}
	#map_canvas
	{
		width:100%;
		height:100%;
	}
	#info
	{
		position:absolute;
		width:250px;
		height:250px;
		left:20px;
		top:300px;
		background-color:white;
		padding:5px;
		overflow:auto;
	}
    &lt;/style&gt;

	&lt;script type=&quot;text/javascript&quot; src=&quot;http://www.google.com/jsapi&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;http://maps.google.com/maps/api/js?sensor=false&quot;&gt;&lt;/script&gt;	

	&lt;script type=&quot;text/javascript&quot;&gt;
	var map;
	var geocoder;

	function initialize() {

		//Geocoder initialization &amp; visitor's location map centering
		geocoder = new google.maps.Geocoder();
		if (google.loader.ClientLocation)
		{
			//Search for visitor's latitude and longitude
			var latt = google.loader.ClientLocation.latitude;
			var longg = google.loader.ClientLocation.longitude;

			//Center the map at visitor's coordinates
			var latlng = new google.maps.LatLng(latt,longg);
		}
		else
		{
			//If we can't get visitor's coordinates, set Madrid as map center
			var latlng = new google.maps.LatLng(&quot;40.41153868&quot;,&quot;-3.70362707&quot;);
		}

		//Create the map
		var myOptions = {
		zoom: 5,
		center: latlng,
		mapTypeId: google.maps.MapTypeId.ROADMAP
		};
		map = new google.maps.Map(document.getElementById(&quot;map_canvas&quot;), myOptions);

		//Add a listener, it will activate when the map become fully loaded
		google.maps.event.addListener(map, 'bounds_changed',function()
			{
				//First div's update to show actual location details
				actualizaUbicacion();
				//Map fully loaded, clear the listener
				google.maps.event.clearListeners(map, 'bounds_changed');
				//And add two new events, one will update the div's info when user ends dragging the map and the other when map's zoom changes
				google.maps.event.addListener(map, 'dragend',function() { actualizaUbicacion() });
				google.maps.event.addListener(map, 'zoom_changed',function() { actualizaUbicacion() });
			}
		);

	}

	function actualizaUbicacion()
	{

		//Map's center coordinates we'll use for reverse geocoding
		var lattlng = map.getCenter();

		if (geocoder)
		{
			geocoder.geocode({'latLng': lattlng}, function(results, status)
			{
				if (status == google.maps.GeocoderStatus.OK)
				{
					if (results[1])
					{
						var reverse_geo = results[1];

						var text = &quot;&lt;a href='http://mooontes.com/2009/07/30/google-maps-api-v3-javascript-2/'&gt;Back to post at mooontes.com&lt;&quot;+&quot;/a&gt;&lt;br /&gt;&lt;br /&gt;Map center: &quot;
							+ map.getCenter()+ &quot;&lt;br /&gt;&lt;br /&gt;Reverse Geocoding:&lt;br /&gt;&quot;;
						if (reverse_geo.address_components[0]) { text = text + &quot;0: &quot; + reverse_geo.address_components[0].long_name + &quot;&lt;br /&gt;&quot;; }
						if (reverse_geo.address_components[1]) { text = text + &quot;1: &quot; + reverse_geo.address_components[1].long_name + &quot;&lt;br /&gt;&quot;; }
						if (reverse_geo.address_components[2]) { text = text + &quot;2: &quot; + reverse_geo.address_components[2].long_name + &quot;&lt;br /&gt;&quot;; }
						if (reverse_geo.address_components[3]) { text = text + &quot;3: &quot; + reverse_geo.address_components[3].long_name + &quot;&lt;br /&gt;&quot;; }
						if (reverse_geo.address_components[4]) { text = text + &quot;4: &quot; + reverse_geo.address_components[4].long_name + &quot;&lt;br /&gt;&quot;; }

						text = text + &quot;5: &quot; + reverse_geo.formatted_address;

						document.getElementById('info').innerHTML = text;
					}
				}
				else
				{
					document.getElementById('info').innerHTML = &quot;No hay información de Reverse Geocoding.&quot;;
				}
			});
		}
	}

	//--&gt;&lt;/script&gt;

&lt;/head&gt;
&lt;body onload=&quot;initialize()&quot;&gt;
	&lt;div id=&quot;map_canvas&quot;&gt;&lt;/div&gt;
	&lt;div id=&quot;info&quot;&gt;&lt;a href=&quot;http://mooontes.com/2009/07/30/google-maps-api-v3-javascript-2/&quot;&gt;Back to post at mooontes.com&lt;/a&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2009/07/30/google-maps-api-v3-javascript-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Maps API V3 (javascript)</title>
		<link>http://mooontes.com/2009/07/29/google-maps-api-v3-javascript/</link>
		<comments>http://mooontes.com/2009/07/29/google-maps-api-v3-javascript/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 20:07:52 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[programacion]]></category>
		<category><![CDATA[api v3]]></category>
		<category><![CDATA[google maps]]></category>
		<category><![CDATA[google maps api v3]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[reverse geocoding]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=295</guid>
		<description><![CDATA[Aunque el API V3 de Google Maps aún está bastante verde y le falta mucho por pulir, ya es bastante usable y si sólo necesitamos las características básicas de Google Maps nos puede servir para nuestro proyecto. Este código es un ejemplo del uso de varias técnicas con javascript: Centrar el mapa en la ubicación [...]]]></description>
			<content:encoded><![CDATA[<p>Aunque el API V3 de Google Maps aún está bastante verde y le falta mucho por pulir, ya es bastante usable y si sólo necesitamos las características básicas de Google Maps nos puede servir para nuestro proyecto.</p>
<p>Este código es un ejemplo del uso de varias técnicas con javascript:</p>
<ul>
<li>Centrar el mapa en la ubicación del visitante</li>
<li>Captura de eventos</li>
<li>Reverse Geocoding</li>
<li>Uso de la <a href="http://google-maps-utility-library-v3.googlecode.com/svn/tags/scrollwheelzoom/1.0/docs/examples.html">librería de Nianwei</a> para hacer zoom con la rueda del ratón (aún no soportado oficalmente en la V3)</li>
</ul>
<p><span id="more-295"></span></p>
<h3 style="clear:both;padding:20px;width:200px;text-align:center;margin:0px auto;"><a href="http://mooontes.com/codigo/google_maps_api_v3.html" target="_blank">Probar el código</a></h3>
<p>Y aquí dejo el código, XHTML con doctype y <a href="http://validator.w3.org/check?uri=http://mooontes.com/codigo/google_maps_api_v3.html">validable</a>, a diferencia de lo que nos tiene acostumbrados google <img src='http://mooontes.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<pre class="brush: xml; title: ; notranslate">
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;!--
** Creado en Julio de 2009 por Montes http://mooontes.com
** Bajo licencia http://creativecommons.org/licenses/by/3.0/es/deed.es
**
** Ejemplo de programación con Google Maps API V3
**
** Centrado del mapa en la ubicación del visitante, captura de eventos,
** reverse geocoding y uso de la libreria para hacer zoom con la rueda del ratón
--&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;es&quot; lang=&quot;es&quot;&gt;
&lt;head&gt;

	&lt;meta name=&quot;viewport&quot; content=&quot;initial-scale=1.0, user-scalable=no&quot; /&gt;
	&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;

	&lt;title&gt;Test Google Maps API V3 -mooontes.com-&lt;/title&gt;

    &lt;style type=&quot;text/css&quot;&gt;
	html
	{
		border:0;
		padding:0;
		margin:0;
		width:100%;
		height:100%;
	}
	body
	{
		border:0;
		padding:0;
		margin:0;
		width:100%;
		height:100%;
	}
	#map_canvas
	{
		width:100%;
		height:100%;
	}
	#info
	{
		position:absolute;
		width:250px;
		height:250px;
		left:20px;
		top:300px;
		background-color:white;
		padding:5px;
		overflow:auto;
	}
    &lt;/style&gt;

	&lt;script type=&quot;text/javascript&quot; src=&quot;http://www.google.com/jsapi&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;http://maps.google.com/maps/api/js?sensor=false&quot;&gt;&lt;/script&gt;	

	&lt;script type=&quot;text/javascript&quot;&gt;
	var map;
	var geocoder;

	function initialize() {

		//Inicializamos geocoder y centramos el mapa en la ubicación del visitante
		geocoder = new google.maps.Geocoder();
		if (google.loader.ClientLocation)
		{
			//Averiguamos latitud/longitud del visitante
			var latt = google.loader.ClientLocation.latitude;
			var longg = google.loader.ClientLocation.longitude;

			//Centramos el mapa en sus coordenadas
			var latlng = new google.maps.LatLng(latt,longg);
		}
		else
		{
			//Si no localizamos la ubicacion del visitante, centramos el mapa en Madrid
			var latlng = new google.maps.LatLng(&quot;40.41153868&quot;,&quot;-3.70362707&quot;);
		}

		//Creamos el mapa
		var myOptions = {
		zoom: 5,
		center: latlng,
		mapTypeId: google.maps.MapTypeId.ROADMAP
		};
		map = new google.maps.Map(document.getElementById(&quot;map_canvas&quot;), myOptions);

		//Añadimos un listener, se activará cuando el mapa esté totalmente cargado
		google.maps.event.addListener(map, 'bounds_changed',function()
			{
				//Primera actualización del div que muestra los detalles de la ubicacion actual
				actualizaUbicacion();
				//Al haber cargado totalmente el mapa, eliminamos este listener
				google.maps.event.clearListeners(map, 'bounds_changed');
				//Y añadimos dos, uno se activará cuando se termine de arrastrar el mapa y otro cuando se cambie el nivel de zoom
				google.maps.event.addListener(map, 'dragend',function() { actualizaUbicacion() });
				google.maps.event.addListener(map, 'zoom_changed',function() { actualizaUbicacion() });
			}
		);

	}

	function actualizaUbicacion()
	{

		//Coordenadas del centro del mapa que usaremos para el reverse geocoding
		var lattlng = map.getCenter();

		if (geocoder)
		{
			geocoder.geocode({'latLng': lattlng}, function(results, status)
			{
				if (status == google.maps.GeocoderStatus.OK)
				{
					if (results[1])
					{
						var reverse_geo = results[1];

						var text = &quot;&lt;a href='http://mooontes.com'&gt;mooontes.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Map center: &quot;
							+ map.getCenter()+ &quot;&lt;br /&gt;&lt;br /&gt;Reverse Geocoding:&lt;br /&gt;&quot;;
						if (reverse_geo.address_components[0]) { text = text + &quot;0: &quot; + reverse_geo.address_components[0].long_name + &quot;&lt;br /&gt;&quot;; }
						if (reverse_geo.address_components[1]) { text = text + &quot;1: &quot; + reverse_geo.address_components[1].long_name + &quot;&lt;br /&gt;&quot;; }
						if (reverse_geo.address_components[2]) { text = text + &quot;2: &quot; + reverse_geo.address_components[2].long_name + &quot;&lt;br /&gt;&quot;; }
						if (reverse_geo.address_components[3]) { text = text + &quot;3: &quot; + reverse_geo.address_components[3].long_name + &quot;&lt;br /&gt;&quot;; }
						if (reverse_geo.address_components[4]) { text = text + &quot;4: &quot; + reverse_geo.address_components[4].long_name + &quot;&lt;br /&gt;&quot;; }

						text = text + &quot;5: &quot; + reverse_geo.formatted_address;

						document.getElementById('info').innerHTML = text;
					}
				}
				else
				{
					document.getElementById('info').innerHTML = &quot;No hay información de Reverse Geocoding.&quot;;
				}
			});
		}
	}

	//--&gt;&lt;/script&gt;

&lt;/head&gt;
&lt;body onload=&quot;initialize()&quot;&gt;
	&lt;div id=&quot;map_canvas&quot;&gt;&lt;/div&gt;
	&lt;div id=&quot;info&quot;&gt;&lt;a href=&quot;http://mooontes.com&quot;&gt;mooontes.com&lt;/a&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2009/07/29/google-maps-api-v3-javascript/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ajustar el tamaño de las fotos en SMF (Simple Machines Forum)</title>
		<link>http://mooontes.com/2009/06/15/ajustar-el-tamano-de-las-fotos-en-smf-simple-machines-forum/</link>
		<comments>http://mooontes.com/2009/06/15/ajustar-el-tamano-de-las-fotos-en-smf-simple-machines-forum/#comments</comments>
		<pubDate>Mon, 15 Jun 2009 13:43:11 +0000</pubDate>
		<dc:creator>montes</dc:creator>
				<category><![CDATA[programacion]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[smf]]></category>

		<guid isPermaLink="false">http://mooontes.com/?p=245</guid>
		<description><![CDATA[Si tienes un foro en SMF (Simple Machines Forum), una de las opciones que no deberías activar nunca es la de ajustar automáticamente el tamaño de las fotos, ya que implica que cada vez que alguien escribe un mensaje que incluye fotos, el servidor se descargará todas las fotos del mensaje para comprobar su tamaño [...]]]></description>
			<content:encoded><![CDATA[<p>Si tienes un foro en SMF (<a href="http://www.simplemachines.org">Simple Machines Forum</a>), una de las opciones que no deberías activar nunca es la de ajustar automáticamente el tamaño de las fotos, ya que implica que cada vez que alguien escribe un mensaje que incluye fotos, el servidor se descargará todas las fotos del mensaje para comprobar su tamaño antes de que el mensaje se publique, con la consiguiente pérdida de tiempo y de paciencia del usuario.</p>
<p>En nuestro caso tenemos un foro con SMF2 y un movimiento de unos 1.200 mensajes diarios, con lo que realizar esta tarea manualmente (que es la única alternativa que queda) se hace bastante pesado.</p>
<p>La solución que he encontrado es escribir un pequeño programa en PHP que se ejecutará una vez al día gracias a <a href="http://es.wikipedia.org/wiki/Cron_%28unix%29">cron</a> y que realizará esta tarea por nosotros.<br />
<span id="more-245"></span><br />
Lo que hace este script es comprobar el tamaño de las fotos de los mensajes que se han escrito durante las últimas 24 horas y en el caso de que el tamaño exceda los 800 pixels de ancho, sustituirá la etiqueta <em>[IMG]</em> por <em>[IMG width=800]</em>, lo que evitará esas fotos gigantes que estropean la normal lectura del foro, además nos enviará un correo con la lista de mensajes que haya modificado.</p>
<p>Este es el script (bajo <a href="http://creativecommons.org/licenses/by/3.0/es/deed.es">licencia CC</a> como es habitual por aquí). Sólo ha sido testeado con SMF2, aunque no creo que haya mucho problema para hacerlo funcionar con SMF1.</p>
<p>Para hacerlo funcionar en vuestro servidor sólo tenéis que modificar la primera línea <em>require_once</em> con la ruta de vuestro <em>Settings.php</em> de SMF, la segunda línea asignando la variable <em>$to</em> al correo donde queréis recibir el resumen diario de mensajes modificados y la tercera línea asignando a <em>$url_foro</em> la dirección de vuestro foro. Y luego por supuesto añadir la tarea para que se ejecute diariamente.</p>
<pre class="brush: php; title: ; notranslate">
	//***
	//Creado Junio 2009 por Montes http://mooontes.com
	//Bajo licencia http://creativecommons.org/licenses/by/3.0/es/deed.es
	//***
	require_once(&quot;/ruta/Settings.php&quot;);  //la configuracion de la BD la cogemos del archivo de configuracion de SMF
	$to = &quot;correo@mail.com&quot;;
	$url_foro = &quot;www.foro.com&quot;;

	$mysqli = new mysqli($db_server,$db_user,$db_passwd,$db_name);

	$mail = &quot;Fotos modificadas hoy &quot;.date(&quot;d/m/Y&quot;).&quot;\n\n&quot;;

	//Comprobamos conexion
	if (mysqli_connect_errno())
	{
		printf(&quot;Connect failed: %s\n&quot;, mysqli_connect_error());
		exit();
	}	

	//Buscamos todos los mensajes con fotos de las ultimas 24 horas
	$sql = &quot;SELECT id_msg,id_topic,body FROM smf_messages WHERE DATE(FROM_UNIXTIME(poster_time))&quot;.
			&quot;&gt; DATE_SUB(DATE(NOW()), INTERVAL 1 DAY) AND body LIKE '%[IMG]http%'&quot;;
	if ($result = $mysqli-&gt;query($sql))
	{
		while($row = $result-&gt;fetch_assoc())
		{
			$body = $row[&quot;body&quot;];
			echo &quot;\n****msg: &quot;.$row[&quot;id_msg&quot;].&quot; topic: &quot;.$row[&quot;id_topic&quot;].&quot;, buscando imagenes...\n\n&quot;;

			//Comprobamos imagen x imagen
			preg_match_all(&quot;%\[img\]([^\[]*)\[/img\]%i&quot;, $row[&quot;body&quot;], $encuentra, PREG_PATTERN_ORDER);
			for ($j = 0; $j &lt; count($encuentra[1]); $j++)
			{
				echo &quot;una foto: &quot;.$encuentra[1][$j].&quot;\n&quot;;
				if (list($ancho, $altura, $tipo, $atr) = getimagesize($encuentra[1][$j]))
				{
					echo &quot;ancho: &quot;.$ancho.&quot; alto: &quot;.$altura.&quot;\n&quot;;
					if ($ancho &gt; 800)
					{
						echo &quot;Tamanyo mayor de 800, vamos a reemplazar...\n&quot;;
						//Mas ancha de 800 pixels? anyadimos width=800
						$body = str_ireplace(&quot;[img]&quot;.$encuentra[1][$j].&quot;[/img]&quot;, &quot;[img width=800]&quot;.$encuentra[1][$j].&quot;[/img]&quot;, $body);
						//actualizamos en la bd
						$bodys = addslashes($body);
						$sql = &quot;UPDATE smf_messages SET body = '&quot;.$bodys.
							&quot;', modified_time=UNIX_TIMESTAMP(), modified_name='bot' WHERE id_msg = &quot;.$row[&quot;id_msg&quot;];
						$mysqli-&gt;query($sql);
						echo &quot;Actualizada la BD\n&quot;;
						$mail .= &quot;Modificada foto en: http://&quot;.$url_foro
						.&quot;/index.php?topic=&quot;.$row[&quot;id_topic&quot;].&quot;.msg&quot;.
						$row[&quot;id_msg&quot;].&quot;#msg&quot;.$row[&quot;id_msg&quot;].&quot;\n&quot;;
					}
				}
				else
				{
					echo &quot;Tamanyo desconocido\n&quot;;
				}
			}
		}
	}

    $result-&gt;close();
    unset($row);
    unset($sql);
    unset($query);

	if ($mail != &quot;Fotos modificadas hoy &quot;.date(&quot;d/m/Y&quot;).&quot;\n\n&quot;)
	{
		$subject = &quot;Fotos arregladas dimensiones &quot;.date(&quot;d/m/Y&quot;);
		if (mail($to, $subject, $mail))
		{
			echo(&quot;Mensaje enviado\n&quot;);
		}
		else
		{
			echo(&quot;Fallo al enviar mensaje...\n&quot;);
		}
	}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://mooontes.com/2009/06/15/ajustar-el-tamano-de-las-fotos-en-smf-simple-machines-forum/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

