OCR using the new open Google Cloud Vision API

Just create a new api key in the developer console, replace it in the code below and it should work. Then you can call "whatever_you_call_the_file.rb /Downloads/some_image_with_text.jpg" and google will OCR-it and the script will print out the recognized text.
require "base64"
require 'net/http'
require 'json'

# Base 64 the input image
b64_data = Base64.encode64(File.open(ARGV[0], "rb").read)

# Stuff we need
api_key = "<YOUR_GOOGLE_API_KEY>"
content_type = "Content-Type: application/json"
url = "https://vision.googleapis.com/v1/images:annotate?key=#{api_key}"
data = {
  "requests": [
      "image": {
        "content": b64_data
      "features": [
          "type": "TEXT_DETECTION",
          "maxResults": 1

# Make the request
url = URI(url)
req = Net::HTTP::Post.new(url, initheader = {'Content-Type' =>'application/json'})
req.body = data
res = Net::HTTP.new(url.host, url.port)
res.use_ssl = true

# res.set_debug_output $stderr

detected_text = ""
res.start do |http| 
  puts "Querying Google for image: #{ARGV[0]}"
  resp = http.request(req)
  # puts resp
  json = JSON.parse(resp.body)
  # puts json
  if json && json["responses"] && json["responses"][0]["textAnnotations"] && json["responses"][0]["textAnnotations"][0]["description"]
    detected_text = json["responses"][0]["textAnnotations"][0]["description"]

puts "Google says the image is: #{detected_text}"

Lock and unlock Ubuntu using your iPhone

If, like me, you suffer from lazius extremis (lazy bastard, for the layman), you probably hate having to lock your computer when you leave and entering a password when you come back.

Fear not, young padawan, UDEV and xdotool to the rescue!

Here's how it works: UDEV (a linux mechanism that detects device events (including USB)) can be configured with rules that fire whenever something changes (i.e. a device is connected or disconnect from the system). When that happens, you want to run a script to lock or unlock your system, based on the type of rule that was fired. So, let's get started:

1. Create the UDEV rules:
1.1. Create a new file at /etc/udev/rules.d/100-lock-unlock-with-iphone.rules, with the following contents:

SUBSYSTEM=="usb", ENV{PRODUCT}=="2bc/12c8/520", ENV{DEVTYPE}=="usb_device", ACTION=="add",    RUN+="/home/youruser/bin/unlock"
SUBSYSTEM=="usb", ENV{PRODUCT}=="2bc/12c8/520", ENV{DEVTYPE}=="usb_device", ACTION=="remove", RUN+="/home/youruser/bin/lock"

1.2. In those lines, replace 2bc/12c8/520 with your device product id, which you can find running the following command in the terminal:

udevadm monitor --environment -u | grep PRODUCT

1.3. Disconnect or connect your iphone and you should see something like this:


1.4. That's the value you put in the rules.
1.5. Replace youruser with your own user name, by the way.

2. Which leaves us with the /home/youruser/bin/lock and unlock scripts to create. Here is the lock script:

export XAUTHORITY=/home/youruser/.Xauthority
export DBUS_SESSION_BUS_ADDRESS=`ps -u youruser e | grep -Eo 'dbus-daemon.*address=unix:abstract=/tmp/dbus-[A-Za-z0-9]{10}' | tail -c35`
echo `date` "-" `whoami` "- Locking system..." >> $log
su youruser -c "DISPLAY=:0 gnome-screensaver-command -a"
echo `date` "-" `whoami` "- System locked!" >> $log

2.1. Again, replace youruser with your own.
2.2. You might be wondering what those lines about DBUS and the X server are all about. The reason for those is that UDEV runs stuff as root. And we want to lock and unlock the screen as our own user. Those lines make sure of that.
2.3. For the unlock script we need to install a tool called xdotool. It's basically an automation command that allows you to make the computer type stuff and control the mouse automatically. The reason to use this is because there is no way in hell you can unlock a locked screensaver (believe me, i've tried). This tool simulates user input (moves the mouse a little bit and the enters your password and presses enter). I know it's not the most secure thing in the world but it's the only way i could make it work. Install it with:

sudo apt-get install xdotool

2.4. Here's the unlock script:

 export XAUTHORITY=/home/youruser/.Xauthority
 export DBUS_SESSION_BUS_ADDRESS=`ps -u youruser e | grep -Eo 'dbus-daemon.*address=unix:abstract=/tmp/dbus-[A-Za-z0-9]{10}' | tail -c35`
 echo `date` "-" `whoami` "- Unlocking system..." >> $log
 export DISPLAY=:0
 xdotool mousemove 0 0 && xdotool type yourpassword && xdotool key Return
 echo `date` "-" `whoami` "- System unlocked!" >> $log

2.5. Replace youruser with your own user and yourpassword with your user password.

3. Reload the UDEV rules with:

sudo udevadm control --reload-rules

4. And now when you disconnect your phone from the computer, it should lock it. When you plug it back in it should unlock.

5. Happy hacking!

Hammerspoon - OSX automation in Lua for the win

For those who don't know, Hammerspoon is a fantastic automation tool for OS X.  It's basically a bridge between the operating system and the Lua scripting language. With its set of extensions (which you can write your own, by the way) you can automate pretty much anything.

You can write Lua code that interacts with OS X APIs for applications, windows, mouse pointers, filesystem objects, audio devices, batteries, screens, low-level keyboard/mouse events, clipboards, location services, wifi, and more.

Here's the current script i'm using on my development laptop. It currently does the following:

  • Auto reloads whenever i change the configuration script;
  • Sets up a menu bar button so i can control whether my laptop goes to sleep or is continuously awake. If you know the app Caffeine, you know what i'm saying;
  • Monitors my Wifi connection and warns me when i lose connection or connect to a different SSID;
  • Monitors my battery and warns me when i get to 10 and 5%.
  • Work in progress: Monitor google.com and bing.com from times to times to check if i have Internet connection.

The great thing about it is its simplicity. Even if you don't know Lua, you'll find it very easy to write simple watchers and callbacks.

Give it a try! :)


-- Auto Reloading when config changes
function reload_config(files)
  -- Kill bat watcher
  if batWatcher then
  -- Kill wifi watcher
  if wifiWatcher then
  -- Kill caffeine
  if caffeine then
  -- Reload config
hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", reload_config):start()
hs.alert.show("Config reloaded")

-- Keep display on or allow going to sleep
local caffeine = hs.menubar.new()
function setCaffeineDisplay(state)
    if state then
function caffeineClicked()
if caffeine then

-- Network connection and disconnection
local wifiWatcher = nil
function ssidChangedCallback()
    newSSID = hs.wifi.currentNetwork()
    if newSSID then
      hs.alert.show("Network connected: " .. newSSID)
      hs.alert.show("Network lost :(")
wifiWatcher = hs.wifi.watcher.new(ssidChangedCallback)

-- Battery Low warnings
local batWatcher = nil
local lastBatVal = hs.battery.percentage()
function batPercentageChangedCallback()
  currentPercent = hs.battery.percentage()
  if currentPercent == 10 and lastBatVal > 10 then
    hs.alert.show("Getting low on juice...")
  if currentPercent == 5 and lastBatVal > 5 then
    hs.alert.show("Captain, she can't take any more!")
  lastBatVal = currentPercent
batWatcher = hs.battery.watcher.new(batPercentageChangedCallback)

--status, data, headers = hs.http.get("http://example.com")

Problem starting Sidekiq in development

If you ever get this error:

can't link outside actor context

Followed by something like:

    /Library/Ruby/Gems/2.0.0/gems/celluloid-0.16.0/lib/celluloid.rb:176:in `new_link'
    /Library/Ruby/Gems/2.0.0/gems/sidekiq-3.3.4/lib/sidekiq/launcher.rb:21:in `initialize'
    /Library/Ruby/Gems/2.0.0/gems/sidekiq-3.3.4/lib/sidekiq/cli.rb:81:in `new'
    /Library/Ruby/Gems/2.0.0/gems/sidekiq-3.3.4/lib/sidekiq/cli.rb:81:in `run'
    /Library/Ruby/Gems/2.0.0/gems/sidekiq-3.3.4/bin/sidekiq:8:in `<top (required)>'
    /Library/Ruby/Gems/2.0.0/bin/sidekiq:23:in `load'
    /Library/Ruby/Gems/2.0.0/bin/sidekiq:23:in `<main>'

It's mostly likely somehow related with either ZenTest or another testing framework. 

In my case, i was adding the ZenTest gem both in the development and test groups of my Gemfile. Moving it away from the development group solved the problem.

AES encryption in Ruby and Decryption in Java

This one is precious, as it took me a long time to figure out. As a side-note, Java apparently only supports 128bit AES.

Here's the Ruby code:

def encrypt(string, pwd)
    salt = OpenSSL::Random.random_bytes(16)

    # prepare cipher for encryption
    e = OpenSSL::Cipher.new('AES-128-CBC')

    # next, generate a PKCS5-based string for your key + initialization vector
    key_iv = OpenSSL::PKCS5.pbkdf2_hmac_sha1(pwd, salt, 1024, e.key_len+e.iv_len)
    key = key_iv[0, e.key_len]
    iv  = key_iv[e.key_len, e.iv_len]

    # now set the key and iv for the encrypting cipher
    e.key = key
    e.iv  = iv

    # encrypt the data!
    encrypted = '' << e.update(string) << e.final
    [encrypted, iv, salt].map {|v| ::Base64.strict_encode64(v)}.join("--")   

And the Java part:

public static String decrypt(String encrypted, String pwd) throws Exception {

        String[] parts = encrypted.split("--");
        if (parts.length != 3) return null;

        byte[] encryptedData = Base64.decodeBase64(parts[0]);
        byte[] iv = Base64.decodeBase64(parts[1]);
        byte[] salt = Base64.decodeBase64(parts[2]);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(pwd.toCharArray(), salt, 1024, 128);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey aesKey = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv));

        byte[] result = cipher.doFinal(encryptedData);
        return new String(result, "UTF-8");