After installing all 4 Ubuntu VMs, then installing 10gen’s Mongodb package, then I went to restore my dump inside the replicaset. For my surprise:

root@mongo0:~# mongorestore --db my_database dump/my_database/
connected to: 127.0.0.1
terminate called after throwing an instance of 'std::runtime_error'
  what():  locale::facet::_S_create_c_locale name not valid
Aborted (core dumped)

A lot of people around says you have to edit /etc/locale.gen, then regenerate locales using locale-gen. For me it didn’t work. But as the problem comes from locales, then the solution was easy:

root@mongo0:~# env LC_ALL=en_US.UTF-8 mongorestore --db my_database dump/my_database/

That’s it.

Are you usually deploying your Ruby applications with Capistrano and want to run remote commands depending on the server IP?

A not very well documented trick is to interpolate the special string $CAPISTRANO:HOST$ on your command. For example:

server_ip = capture("echo $CAPISTRANO:HOST$").strip
run "I'm running on server #{server_ip}"

The problem comes when you’re deploying to multiple servers, like this:

role :app, '192.168.1.1', '192.168.1.2'

task :some_task, :role => :app do
  server_ip = capture("echo $CAPISTRANO:HOST$").strip
  run "I'm running on server #{server_ip}"
end

This will always print your app’s role first ip, 192.168.1.1.

The solution is even less documented:

role :app, '192.168.1.1', '192.168.1.2'

task :some_task, :role => :app do
  find_servers_for_task(current_task).each do |current_server|
    run "I'm running on server #{current_server.host}"
  end
end

You know that ruby hype which claims “no need to document things, simply read the code”… well, that’s the reason for blog posts like this one. A mess.

Os presento el nuevo proyecto que emprendo junto a mis compañeros Miguel de Lucas (Pepecar, Pepephone, Pepetravel) y Jaime Herraiz (WET, North Kites), ambos personas de referencia en los ámbitos del e-commerce y los deportes de playa respectivamente.

Spotfav es un site que sirve a los que practican deportes al aire libre para saber las condiciones de su spot antes de desplazarse. Para ello contamos con la instalación de cámaras HD y estaciones meteorológicas en los spots más demandados. Por supuesto todo ello rodeado de una capa social, móvil y geoposicionada… es un proyecto bonito y ambicioso :-)

¿Cómo funciona?

Pues es muy fácil. Parte de la acción transcurre en la aplicación móvil, y parte transcurre en la web.

  • Te bajas la aplicación de móvil para iPhone o Android
  • Te vas a la playa y desde la aplicación creas el spot. Así te conviertes en su Marshall, lo que en un futuro te dará acceso a ofertas exclusivas en esa zona.
  • Reportas las condiciones del tiempo de los spots a los que acudes, desde la misma aplicación. Puedes reportar en público (para todos) o en privado (para informar sólo a un grupo de amigos).

Desde la web podrás visitar los spots, hacerte fan de los que más te gusten, establecer conversaciones con la gente que está reportando en la playa y hacerte una red de amigos que podrás organizar en listas.

Los favs

El fav es la moneda de cambio dentro de Spotfav. Cuando te registras recibes 5 favs, y con ellos puedes votar en tus spots favoritos para que se coloque una cámara o una estación meteorológica.

Si se llega al mínimo de favs, colocamos una cámara y una estación meteorológica. Así, sin anestesia. En cualquier spot. En cualquier parte del mundo.

Si te gusta hacer surf, pesca, snorkel, volley-playa… tienes que crear tus spots en Spotfav. Y tienes que votar para que les pongamos una cámara. Y tienes que hacerte una red de amigos a los que informar (y que ellos te informen a tí) del estado del tiempo. Porque Spotfav es el sitio.

¿Y cuando has gastado tus 5 favs, cómo consigues más? Muy fácil: trayendo a tus amigos.
En la web hay un sistema de búsqueda e invitación de amigos que te permite localizar a tus contactos de Facebook, Twitter y tu agenda de Gmail. Cada amigo que se registre usando tus invitaciones, te dará 1 fav.

Widgets

Además, si te gusta alguna cámara en especial puedes empotrarla en tu web o blog. Disponemos do dos widgets (como los que ves en este mismo blog) a dos tamaños diferentes. El grande es de 300×300, y el pequeño de 200×200. Con ellos podrás mostrar nuestras cámaras en tu web, como un servicio adicional para tus clientes o usuarios. En los widgets se muestra un frame cada 15 minutos, y pulsando la imágen el usuario va a la cámara en Spotfav, donde podrá ver el streaming en tiempo real.

Además, cada persona que venga a través de tus widgets y se registre te dará 1 fav :-D

¿Sólo playa?

Mis compañeros Jaime y Miguel son surferos muy activos. En especial Jaime (conocido en algunos círculos como Oru) que es uno de los precursores del kitesurf y el windsurf, y una de las personalidades más importantes de España en este entorno. Por esa razón la comunidad en la que más rápido hemos entrado es en la surfera.
Nuestras primeras cámaras están localizadas en Tarifa y sus alrededores. La semana que viene vamos a colocar 2 más en Catalunya (en Castelldefels y en Sant Pere Pescador), y 1 en Huelva (Punta Umbría). En breve vamos a tener varias en el País Vasco, donde todavía estamos negociando zonas.

No obstante en un plazo breve de tiempo vamos a llegar también a la montaña. No tardaremos mucho :-D

¿Y el negocio?

Estamos actualmente en pleno desarollo de la parte de monetización, que es una aplicación considerablemente grande dentro de Spotfav. Se trata de Spotfav Places, un sistema de publicación de ofertas geolocalizadas con redención a través de telefonía móvil.
Es decir, que los comercios de los spots van a poder publicar ofertas geoposicionadas, colocar publicidad en web y móvil, mantener una base de datos de sus clientes y disponer de las herramientas para comunicarse con ellos.

A nivel de tecnología

El site está programado con Ruby on Rails (3.1 a día de hoy), sobre una base de datos MongoDB. El streaming de las cáaras se hace con Vlc-server y está automatizado a base de colas de trabajos en Resque. Los servidores de snapshots y streaming motion-JPG están programados en Ruby con Sinatra. Y en general el resto del stack es el habitual… Nginx, Rails con Unicorn, Sinatra con Thin, Mongodb, Redis para el gestor de colas Resque, y Postfix con un buen setup de políticas antispam para el relay de newsletters, que se hace desde nuestra propia infraestructura.

La aplicación para iPhone y Android es obra de Marc Planagumà, nuestro developer de movilidad multiplataforma. Está desarrollada sobre Phonegap, y aunque actualmente sólo está disponible para las plataformas mayoritarias es previsible que en un futuro lo esté también para Blackberry y Windows Mobile.
Por ahora la aplicación dispone sólo de las funcionalidades de upload de spots y reporting, aunque esta semana van a empezar a llegar los updates: upload de fotos y videos, notificaciones push, gestión de la capa social y la privacidad, búsquedas, favoritos y compartición con aplicaciones de terceros. Nadie dijo que el camino fuese corto ni fácil…

Destacable también es el trabajo de nuestro compañero y teleco de lujo Miguel Andrés, el autor de las estaciones meteorológicas que utilizamos en todos nuestros spots. El diseño, la implementación y hasta el montage es suyo, así como el firmware y el protocolo que transmite a nuestros servidores las condiciones climáticas.
Y si alguien ha pensado en quitárnoslo para hacernos la competencia… atrás bribones, es nuestro, Y tendréis que pasar por encima de mi cadáver ;-D

Eso es todo chicos, espero que nos veamos en el agua (o al menos en Spotfav!).

Os dejo con nuestro lema: CHECK BEFORE YOU GO :-)

ivan.age = 33

I’ve been trying to set up a Motion-JPEG streaming with ruby, for a webcam which uploads a picture per second to a server. I want new images to be served via streaming instead of making the browser call them every second via a javascript call.

I found many different solutions, some of them including EventMachine, which now is not necessary thanks to the new Sinatra 1.3 streaming feature.
The tricky part was related to the headers, the boundary, and the need to send the content type before each image.

For the test I first created a directory and stored some pictures inside

mkdir /tmp/images
# place some jpg pictures here

And the code. My little app looks like this:

# motion_stream.rb
require 'sinatra'
set :server, :thin

get '/' do |dir|
  boundary      = 'some_shit'
  source_dir    = '/tmp/images'

  headers \
    "Cache-Control" => "no-cache, private",
    "Pragma"        => "no-cache",
    "Content-type"  => "multipart/x-mixed-replace; boundary=#{boundary}"

  stream(:keep_open) do |out|
    while true
      file        = random_file(source_dir) # see also latest_file() below
      content     = File.open("#{source_dir}/#{file}", 'rb') { |f| f.read }

      out << "Content-type: image/jpeg\n\n"
      out << content
      out << "\n\n--#{boundary}\n\n"

      sleep 1
    end
  end
end

## get a random image from a directory
##
def random_file(dir)
  files = Dir.entries(dir).collect { |file| file }
  files -= ['.', '..']
  files[rand(files.size)]
end

## ... or get the newest image
## In this case I'm not taking the latest file
## uploaded by the camera, but the previous one.
## This is to avoid grabbing a currently uploading
## file, which may be shown as corrupt or incomplete.
##
def latest_file(dir)
  files = Dir.entries(dir).collect { |file| file }.sort { |file2,file1| File.mtime(dir+file1) <=> File.mtime(dir+file2) }
  files -= ['.', '..']
  files[1]
end

Then simply create a Gemfile including Sinatra and Thin, as WebRick is not evented and does not support this kind of stream.

# Gemfile
source :rubygems

gem 'sinatra'
gem 'thin'

And that’s all. Run the app and you’re done.

ruby motion_stream.rb

Just visit http://localhost:4567/ with your browser :-)

Ya expliqué en éste otro post una de las mayores cagadas de seguridad en lo que refiere a comercio electrónico.

Seguí quejándome, me dijeron que tenía que escribirlo en una página de Facebook y así lo hice. Pero nadie me contestó ni volvieron a contactar conmigo, así que entiendo que le dieron importancia 0.

Todo este tiempo he estado comprando online con mi tarjeta, y el bug sigue estando ahí.
Hoy al renovar un servidor he vuelto a pagar con tarjeta y me he vuelto a topar con el marrón. Y he vuelto a hacer la pataleta en Twitter (click para ampliar):

A lo que me han respondido esto:

WHAT THE FUCK???

Será una broma no?
Al personal del Banco Sabadell se le debería caer la cara de vergüenza (algo que por lo visto no tienen). Lo que está en juego es el dinero de sus clientes. Las medidas de seguridad online en los bancos deberían ser EXTREMAS. En el Banco Sabadell no sólamente no lo son, sino que además llevan meses haciendo caso omiso de un fallo grave que yo mismo he reportado reiteradas veces.

Lo próximo al volver de vacaciones será poner una queja formal en mi oficina y cambiarme de banco. Y la próxima vez que denuncie esto será a la policía.

Have you ever written a Facebook application?
One of the most common problems for iframe apps is making canvas auto-resize. It’s solved this way:

    <div id="fb-root"></div>
    <script>
      window.fbAsyncInit = function() {
        FB.init({appId: 'YOUR_APP_ID_HERE', status: true, cookie: true, xfbml: true});
        FB.Canvas.setAutoResize();
      };

      (function() {
        var e = document.createElement('script'); e.async = true;
        e.src = document.location.protocol +
          '//connect.facebook.net/en_US/all.js';
          document.getElementById('fb-root').appendChild(e);
      }());
    </script>

Place this snippet after the body tag, and set your application (at facebook developers config center) to be auto-resizable. And that’s it!

Other common problem is how to make window scroll up when you click on a link. Usually the page renders but leaves you at the same vertical position you were before clicking.
If you are suffering this and you are using jquery, you can solve it this way:

    <script type="text/javascript">
      jQuery(document).ready(function($) {
        scrollTo(0,0);
        FB.Canvas.setSize({width: 760, height:$('body').height()+20});
      });
     
      function scrollTo(x,y){
        $("body").append('<iframe id="scrollTop" style="border:none;width:1px;height:1px;position:absolute;top:-10000px;left:-100px;" src="http://static.ak.facebook.com/xd_receiver_v0.4.php?r=1#%7B%22id%22%3A0%2C%22sc%22%3Anull%2C%22sf%22%3A%22%22%2C%22sr%22%3A2%2C%22h%22%3A%22iframeOuterServer%22%2C%22sid%22%3A%220.957%22%2C%22t%22%3A0%7D%5B0%2C%22iframeInnerClient%22%2C%22scrollTo%22%2C%7B%22x%22%3A'+x+'%2C%22y%22%3A'+y+'%7D%2Cfalse%5D" onload="$(\'#scrollTop\').remove();"></iframe>');
      }
    </script>

Same as before, place this snippet after the body tag and you’re done.

I don’t remember where I got these snippets. Just wanted to share them because they’re really useful, and because I usually forget them and have to rescue backups of older apps heheh

Hope it helps!

Mi empresa opera con el Banco de Sabadell. Tengo con ellos la cuenta de mi pequeño negocio, y tengo una tarjeta con la que suelo hacer las compras de las cosas que voy necesitando.
Las cosas que pago en mano (gasolina, comidas, etc) no tienen problema, pero yo compro muchas cosas por Internet y hay algo que no me gusta.

No sé que tan peligroso o inseguro es, pero el caso es el siguiente:

  • Al realizar una compra por internet, algunos comercios implementan el sistema de Comercio Electrónico Seguro (en adelante CES).
  • Con este sistema, me aparece una pantalla ajena al comercio que me pide una clave de mi tarjeta de coordenadas.
  • Normalmente la tarjeta de coordenadas se usa para activar operaciones en la página del banco (transferencias, domiciliaciones, etc), pero en el caso de comercios con CES también se usa para activar una compra.
  • La tarjeta tiene 80 coordenadas, con 80 claves distintas
  • Cada vez que compro (literalmente), el sistema me pide SIEMPRE la misma coordenada. La 01, para ser más exactos.

Al principio pensé que era una coincidencia, ya que estoy en el Banco Sabadell desde hace poco. Pero después de hacer muchas compras me doy cuenta de que no lo es.

He posteado algunos twitts al respecto, y me ha contactado un chico del @bancosabadell por teléfono. En su conversación me ha explicado que:

  1. La inseguridad no es culpa del banco, sino del CES.
    Como si el CES fuese una entidad aparte y no tuviese nada que ver con el banco.
    Me ha explicado que a cada tarjeta de coordenadas, el sistema de CES le asigna una posición, y que al usuario SIEMPRE se le pide esa posición. Nunca cambia.
    Para mi tranquilidad (urgh…!) me ha explicado que si quiero puedo ir periódicamente a una sucursal y pedir que me cambien la tarjeta de coordenadas.
  2. No es una inseguridad.
    A fin de cuentas, la tarjeta de coordenadas no es algo para llevar encima. Porque si alguien me roba la tarjeta de crédito, tendrá todo lo que necesite para comprar cosas en mi nombre.
    También me ha explicado que es difícil que, si alguien supiese mi coordenada 01, también sepa el número de mi tarjeta y el CVV. Son muchos datos.
    Supongo que no habrá pensado en que para irme a ver a un cliente a Madrid y poder comprar el billete de vuelta desde el hotel, necesito mi tarjeta de coordenadas y mi tarjeta de crédito. Las dos juntas.

Después de esta conversación he seguido twitteando un poco, y un chico al que sigo me ha explicado cómo funciona con su banco. Y me ha hecho recordar que en los otros dos bancos con los que he trabajado anteriormente el CES funciona distinto: en uno me envían un SMS con la clave para activar la compra, y en el otro me piden un pin que sólo sé yo y que puedo cambiar cuando me plazca.
En el caso del pin es un poco engorroso, porque hay unas normas de longitud, restricciones de caracteres etc… pero cualquiera de los dos casos me parecen mucho más seguros que el que a mí me afecta.

¿A alguien más le pasa ésto con su banco?
¿¿Acaso no deberían ser los bancos los que más se preocupasen por la seguridad??

I’m translating my usual sysadmining shellscripts into ruby for fun and practice. One thing I hate from Ruby (maybe the only or the most important one) is its documentation. It is zero browseable and friendly, and makes you waste half of your time trying to find on google which module/class does what you need.

One thing I’ve been trying to find is how to copy a file (OMG!).
Can it be so difficult?? … please, try to find it on File class reference.

You have to figure out that exists a module called FileUtils or its old bro (ruby 1.8.6) ftools. Using them you can easily copy, move, rename and make basic file management.
What I find more surprising is that the File class reference does not mention any of them (Uh!?).

Once I found it the job was easy (using ftools as I’m still on Ruby 1.8.7):

require 'ftools'
File.copy source_file, target_file

Trying to get pure-ftpd running on an OpenVZ virtual server and getting this message?

[ERROR] Unable to switch capabilities : Operation not permitted

Shut the VPS down, enter the host via SSH and enable needed capabilities for your VPS (where $VPS_ID is your VPS id, ie 101, 102…)

for CAP in CHOWN DAC_READ_SEARCH SETGID SETUID NET_BIND_SERVICE NET_ADMIN SYS_CHROOT SYS_NICE CHOWN DAC_READ_SEARCH SETGID SETUID NET_BIND_SERVICE NET_ADMIN SYS_CHROOT SYS_NICE; do vzctl set $VPS_ID --capability ${CAP}:on --save; done

That’s it :-)