tag:pedroassuncao.com,2013:/posts Ramblings Of a Madman 2017-07-25T11:32:12Z Pedro Assunção tag:pedroassuncao.com,2013:Post/1176863 2017-07-25T11:25:45Z 2017-07-25T11:32:12Z Choosing a Ruby gem
Instead of writing yet another list of gems you should be using, i'll try to explain how i choose a gem for a particular task or function. This is by no means a complete checklist, it's just my typical way of going about things.


If you're a Ruby developer you are probably familiar with the website rubygems.org. It's "the" repository for all information about Ruby gems.

Things i find important when looking for a gem:

Number of total downloads

Though it will not tell you whether a gem is any good, it does tell you whether a lot of people looked at it as a good candidate for the job you need done. It's also an indicator for the community you can expect around this gem (helps when looking for tutorials, documentation, and general help).

Release date of the last versions

This will show you how frequently is the gem updated, which is useful to know how fast are fixes and new features introduced.

Sometimes it can happen that a really good gem hasn't had a release in a while. For example a couple of weeks ago i was looking for a gem that wrapped the Marvel Comics API. If you look for gems for that you find that most are really old. Doesn't mean they don't work properly, it just means that the API hasn't changed since and they are still relevant. When that's the case, i usually go for the one that was released last, just because the author had the gift of hindsight over the other ones and might have done a better, more polished job at it. Not always true, but... :)

Dependencies and License

To a lesser degree, i also take a look at these.

The less dependencies a gem has the lighter your code will be. Again, not always true, but it's a good rule of thumb. Also pay attention if the license is compatible with your own project.

    If a particular gem feels like a good candidate, I then visit its...


    There, i usually check for a couple of things:


    This is how you learn how to use the gem, so it helps if the docs are really good (and maintained!).

    If it's an opensource project (which most gems are), then i also look for:

    Last commit date

    A clear indicator of the health of the gem. Also, take into consideration what i wrote earlier about gems that don't update often: it might be because they just don't need to.

    Number of contributors, commenters, discussions

    They show how active the community is around this gem. If big, it helps later when trying to find information how to do things if you get stuck, for example.

    Number of open issues (and resolved)

    If you take a glance at the last issues, when they were created, when they were replied to or resolved, this will also give you a good idea of how active the developers are, and how fast can you expect a response if you report something.


    Looking at the source code, though not as important as the rest, can also provide some insight to how performant, optimized the gem is at the job it does. It might also help you figure out if will be easy to monkey patch something to fit your needs later. And who knows, you mighty also learn something new from it :)


    Though not (by any means) a complete guide for choosing a gem, this might be a good starting point. Also, some of these "metrics" might apply for choosing other software and code libraries.

    Like most things in life, your mileage may vary.

    Happy coding!

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/1136812 2017-03-08T09:27:35Z 2017-03-08T10:00:12Z Java in Firefox after v52.0 (Checkpoint VPN)

    Firefox has changed a few things in its plugin infrastructure and that means Java will no longer work properly after version 52.0 (especially if you are using Checkpoint VPN to access work).

    Fortunately one can always install older versions, present here:


    Also, be sure to disable automatic updates in the settings to prevent the browser from updating itself (default).

    Bonus step (if you are on the mac configuring Checkpoint):

    The newest OSX has a safety feature called SIP (System Integration Protection) that will prevent the checkpoint from installing the required files in the system. To work around this, you need to disable it temporarily:

    • Boot into recovery mode (restart and press Command + R on hearing the beep)
    • Open the terminal and type:
    • csrutil disable
    • Reboot
    • Access the vpn and the snx_extender installation step will work.
    • Go back into recovery and enable SIP again:
    • csrutil enable

    Happy VPN'ing

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/998927 2016-02-22T15:34:18Z 2016-02-22T15:34:32Z 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}"
    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/973146 2016-01-18T09:16:55Z 2016-01-18T09:16:55Z 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!
    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/921201 2015-10-23T15:18:04Z 2015-10-23T15:18:04Z Helium - A floating window for your media [OSX]

    My new favorite application for OSX is called Helium

    It's basically something that allows you to keep an always-on-top window with whatever video (youtube, local, etc.) you want to have playing while you do other things. 

    Pretty awesome!

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/897815 2015-08-26T10:13:15Z 2015-08-26T10:13:15Z OSX - Command line battery cycles information

    Here's how to get the number of battery charging cycles on your laptop on OSX:

        ioreg -l | grep LegacyBatteryInfo | cut -d '{' -f 2 | tr -d \} | tr ',' '=' | awk -F'=' '{print $12}'

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/896205 2015-08-21T10:24:49Z 2015-09-30T06:00:42Z 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")
    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/879443 2015-07-10T15:53:07Z 2015-07-10T15:54:43Z Making video presentations from photos Untitled

    Here's a little Java application i made to make it easier to create video presentations based on images. It allows you to add pictures and superimpose text on them. The resulting video is H264 encoded (and thus very small).

    Source code is available here.

    A prebuilt (ready to use) version can be found here.

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/861225 2015-05-26T16:49:44Z 2015-05-26T16:53:03Z 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.

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/860785 2015-05-25T17:21:19Z 2015-05-25T17:22:22Z Planetary terrain in Unity 3D [video]

    Here's a little something i've been working on in my spare time. Maybe it'll end up as a space game, who knows? :)

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/814863 2015-02-24T17:56:19Z 2015-02-24T18:00:01Z 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");
    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/810704 2015-02-12T13:09:25Z 2015-09-30T05:57:06Z Atlas, the awesome balancing robot...

    ...or "how they are training robots to destroy us soon enough" :)

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/810061 2015-02-11T11:53:13Z 2015-02-11T11:53:13Z Great solution for a camping light, especially if near the coast

    It's a lamp powered by water and salt, i kid you not :)


    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/806310 2015-02-03T12:18:03Z 2015-02-03T12:18:04Z Helicopter pilot goes out of his way to retrieve an RC plane

    Gotta love people using their awesome skills to do some good in the world :)

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/805806 2015-02-02T12:05:47Z 2015-02-02T12:05:48Z Kill process by fuzzy name Sometimes you want to kill a process but you either don’t know the exact name of the executable file, or you know part of the command arguments. killall is not your friend in those situations. Here’s a quick script to grep on part of a process name or arguments and kill it.

    Full script (put it in a path included folder and change it’s permissions to executable +x):

    ps aux | grep $1 | grep -v grep | awk '{print $2}' | xargs kill -9
    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/805794 2015-02-02T11:00:57Z 2015-02-02T11:00:57Z $499 electric bike on indiegogo Too bad it’s US made, shipping would be expensive :(

    Still, pretty cool specs:

    - Top speed of 20mph (around 32 km/h)
    - 50 mile range (80 km)
    - Full battery charge in 90 minutes

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/805057 2015-01-30T17:50:11Z 2015-01-30T18:00:12Z Another awesome video Take a peak inside the most awesome BASE jumping boogie ever created. The 3rd annual AZ BASE Boogie, hosted by Matt Frohlich of anitgravityBASE and also Apex BASE. Witness a sample of what a huge group of awesome jumpers can get themselves into over a big party weekend in the winter desert. Thanks to Matt and all the local jumpers, all the participants and the guys who contributed footage for this video. Absolute success!!! 

    from Vimeo 
    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/804472 2015-01-29T18:30:45Z 2015-01-29T18:30:45Z Working on a RC transmitter FPV screen mount Gotta love 3D printing :)

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/804270 2015-01-29T11:28:31Z 2015-01-29T17:59:55Z Another awesome video from Vimeo 
    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/803871 2015-01-28T17:21:35Z 2015-01-28T17:21:36Z New live show from Louis CK

    This guy is my favorite comedian of today.

    If you have $5 to spare, buy his latest live show. If you love dark, often self-deprecating, intelligent humor you will not regret it :)


    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/803296 2015-01-27T16:22:56Z 2015-01-27T16:22:56Z Web application hacker's toolbox A pretty cool web app that allows you to perform common task related to web development, like URL encode, Base64, MD5, formatting, and a lot more.]]> Pedro Assunção tag:pedroassuncao.com,2013:Post/802877 2015-01-26T18:20:05Z 2015-01-26T18:20:06Z Two awesome sports in one day It’s not every day that you find out about great people in awesome sports.

    First, this guy puts Robin Hood and Legolas to shame with his archery skills. A lot of interesting things about his technique which, once again, comes to show that Hollywood distorts reality like crazy: 

    Second, there are Long Sword fights. For real. Enough said:
    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/802666 2015-01-26T11:06:11Z 2015-01-26T11:06:12Z Avoiding SSL redirect loop
    If you are configuring an nginx website to use SSL and - by any chance - you need to setup more than one “server” entry (for instance to make www redirect to the plain URL), keep in mind that you need to declare the ssl certificate mumbo-jumbo in both entries, otherwise browsers will enter a redirect loop.

    Something like the following will do:

    server {
            listen 443 ssl;
            server_name www.zenblast.com;

            include zenblast-ssl.conf;

            return 301 $scheme://zenblast.com$request_uri;

    server {
            server_name zenblast.com;
            listen              443 ssl;

            include zenblast-ssl.conf;


    zenblast-ssl.conf is where we define stuff like ssl_certificate, ssl_certificate_key, ssl on, ssl_ciphers, ssl_prefer_server_ciphers on, and ssl_protocols. Notice that the file is included in both entries.

    Hope this helps save someone 30 minutes of Googling :)
    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/802025 2015-01-24T15:37:48Z 2015-01-24T15:37:48Z Tell me what to do, i'll tell you who i am

    We can't all be strong.

    In any group where everyone is different, some are stronger and some are weaker. There is a hierarchy of power (no matter what the specific kind is). And every single individual wants to satisfy his own wish of being stronger than his neighbors.

    Now, if you are weak, it's in your best interest to attach yourself to stronger individuals. Because in the end, if they win, you win[^stab]. So you, as a weaker entity, look for leadership in this stronger individual. You will not be his equal, but at least you will be better than other individuals who are stronger than yourself. But the stronger individual also benefits from being in a group. Because then he can take on more than one single individual who might be almost as strong as he his. If he doesn't do this, there is a chance that a couple of slightly-less-stronger than himself will gang up on him.

    [^stab]: Especially if you stab them in the back after you've won :)

    The point here is: everyone wants to be in a group, for one reason or another. And if you are in a group, chances are you do as the group does, no questions asked. Because you don't want to be left out.

    This leads to a very interesting question: Do people like to be told what to do?

    Let's consider this: We have been part of some group or another basically forever. And, if you are in a group, you tend to do as the people of that group do. Multiply this by endless centuries of doing the same thing and - all of the sudden - you have individuals that don't do any thinking at all. The leaders do that for them. That does not mean they like it. It just means that they are so used to it that it's easier to follow orders than to question them, simply because that's what you've been doing all this time.

    And that - i believe - explains things like organized religion, eating fast food every day, or dictatorships. We do these things because other people tell us to do it, be it by ways of tradition, advertising and media[^media], or plain word of mouth. We are so formatted to group thinking that most of the time we don't question these things.

    [^media]: Look into how much money brands put into advertising these days and get ready to have you mind blown. As a bonus, look at a few ads and see how many are implicitly getting you into group thinking mode.

    So do people like to be told what to do? I don't think so. But it sure is easy, don't you agree?

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/802023 2015-01-24T15:36:46Z 2015-01-24T15:36:46Z Fast blogging setup

    ## Static vs Dynamic

    I've maintained my own website/blog for as long as i can remember. Ever since the days of static HTML pages, simple PHP scripts, [Wordpress](http://wordpress.org) installations, [Joomla](http://www.joomla.org), [Drupal](https://www.drupal.org), [Postnuke](http://www.postnuke.com), [PHPNuke](https://www.phpnuke.org), you name it, i've tried it.

    So one day i found out about static site generators. The basic idea is that, instead of having some kind of storage for the content (database), it lives in plain files. The webpages are generated by an engine and can then be served as plain HTML which is - obviously - much faster than any interpreted system (like PHP, Rails, ).

    Here's an example of dynamic page generation like - for instance - a Wordpress installation, or a Ruby on Rails website:

    The biggest problem with this is speed. Since there are so many steps, it can never be as efficient as static HTML pages. Of course you can always cache the requests and make it a bit faster, but i tend to like the path of least resistance :)

    Here's the static generation approach:

    The website pages are generated once and served statically, which is much faster.

    Before i proceed to explain how i've implemented it, let me just say that there are many advantages for a full fledged dynamic website (e-commerce, storing user information, registrations, etc, etc.). But if your only concern is to publish content on the web and allowing readers to comment on it you can easily pull it off with this system, integrating it with something like [Disqus](https://disqus.com/websites/), for comments.

    ## Practical example

    To implement this system we need:

    - **A static website generator**. I chose [Middleman](http://middlemanapp.com/). Others include [Jekyll](http://jekyllrb.com/), [Hugo](http://hugo.spf13.com/, [Pelican](http://blog.getpelican.com/), [Hexo](http://hexo.io/) and [DocPad](http://docpad.org/). - **Some way to transfer the generated files to your server**. [Rsync](http://en.wikipedia.org/wiki/Rsync) is my choice, but you can pull it off in a gazillion ways, including [Dropbox](https://www.dropbox.com) synchronization, for example, or just FTP. - **A web host running a webserver**. In my case i have a [Linode](http://www.linode.com/) with an [Ubuntu](http://www.ubuntu.com) installation that has [Nginx](http://www.nginx.org/) running. Other solutions might include a combination of [Apache](http://httpd.apache.org/), [Dreamhost](http://www.dreamhost.com/), [HTTP Explorer](http://http-explorer.sourceforge.net/), [Bluehost](http://www.bluehost.com/), [LightHTTPD](http://www.lighttpd.net/) and [A Small Orange](http://www.asmallorange.com/)

    ### Step 1 : Install Middleman

    There are plenty of guides on how to install this out there, so i'll just point you to the [getting started guide](http://middlemanapp.com/basics/getting-started/).

    ### Step 2 : Create your pages

    Middleman has a bunch of templates that you can use as a starting point, so check out their fantastic documentation and make it happen. In alternative you can proceed with the example template you should have ended up with if you followed their tutorial.

    ### Step 3 : Middleman commands to know

    Here are the commands you are most likely to use with middleman, and their explanation:

    **Start the development server**, so you can test your site at `http://localhost:4567`:


    **Generate a new blog post**, assuming you installed and set up the [middleman-blog plugin](http://middlemanapp.com/basics/blogging/):

    middleman article "title of your new post"

    **Build the static pages for deployment**:

    middleman build

    **Deploy your pages using middleman**:

    middleman deploy

    ### Step 4 : Deploy

    You don't necessarily need to use the `middleman deploy` command if you don't want to. After you do `middleman build` all your generated content can be found inside the `build` folder on your project root. Deploying it is simply a matter of getting those files into your webserver. And for that you can use any method you prefer.

    I like to let my server do all the work of building and deploying by using the following workflow:

    - I write a post or modify a page - I call a script on my local computer that does the following:

    #!/bin/sh rsync -h -r --delete /data/static-blog/source/* void@blog:/home/void/static-blog/source ssh void@blog "touch /home/void/static-blog/.build"

    First, it copies all of my site's sources into the working folder on the server (this is the step where you could use dropbox, btw). Then it creates a file on that folder (`.build`) that instructs the server to build and deploy the website automatically.

    - The server has a cron job running every X minutes that executes a script:

    */5 * * * * /home/void/bin/build_blog.sh

    And the contents of that script are:

    #!/bin/bash if [ -e "/home/void/static-blog/.build" ] then logger -s "Blog: Starting build..." logger -s "Blog: Sourcing RVM..." source /home/void/.rvm/environments/ruby-2.0.0-p0 logger -s "Blog: Removing order file..." rm /home/void/static-blog/.build logger -s "Blog: Getting into folder..." cd /home/void/static-blog logger -s "Blog: Executing bundle install..." /home/void/.rvm/gems/ruby-2.0.0-p0/bin/bundle install logger -s "Blog: Building files..." /home/void/.rvm/gems/ruby-2.0.0-p0/bin/middleman build logger -s "Blog: Copying files into place..." rsync -h -r --delete build/* /data/static-blog/live/ logger -s "Blog: Build done." fi

    Simply put, the script checks for the existence of the `.build` file inside the working folder and - if so - sets up the environment for bundle, generates the website, and moves the generated files in the `build` folder into the nginx folder i have setup in `/data`. It also removes the trigger `.build` file so the process isn't restarted on the next cron execution.

    ## Conclusion and future work

    I think this is an overall nice setup. Things i would like to improve include not having to trigger the build process. Ideally any change to the blog folder on my laptop should automatically build and deploy the website. Reasons why i haven't been able to do it:

    - Dropbox doesn't seem to trigger file changes for [incron](http://inotify.aiken.cz/?section=incron&page=about&lang=en) (a file system watch service), which sucks. - [inotify](http://inotify.aiken.cz) is an alternative to incron, but unfortunately i've ran into another problem: Changes in files inside the working folder trigger multiple alarms (sometimes more than one per changed file). This means i have no way of knowing if the file syncronization has ended (either by dropbox or rsync) and wether i can start the build process or not. Otherwise i risk building with only half the files in place and that might break the site.

    If you have any ideas on how to make the process more efficient [please share](http://twitter.com/nocivus); i would love to hear all about it.

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/802022 2015-01-24T15:35:20Z 2015-01-24T15:35:20Z Consciousness found?

    This [article](http://www.sciencedaily.com/releases/2014/01/140116085105.htm) explains how scientists found quantum vibrations inside brain neurons, the reason we are sentient beings.

    The now supported theory, called **"orchestrated objective reduction"**, apparently *"(...) opens a potential Pandora's Box, but (our) theory accommodates both these views, suggesting consciousness derives from quantum vibrations in microtubules, protein polymers inside brain neurons, which both govern neuronal and synaptic function, and connect brain processes to self-organizing processes in the fine scale, 'proto-conscious' quantum structure of reality."*

    The lost me at "Pandora" :)

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/802021 2015-01-24T15:34:04Z 2015-01-24T15:34:04Z 'Fish Shell 2.1 messed up prompt'

    If you upgraded to the [Fish Shell](http://fishshell.com) version 2.1 you might have noticed your prompt now containing a bunch of new lines (blank). I believe it's due to the fact that the **echo** command now produces a new line by default (even though that's not explicitly stated in the [release notes](http://fishshell.com/release_notes.html)) [1](#note).

    To solve it, replace all ocurrences of echo in your Fish prompt function with **echo -n \**. This will tell echo to not end with a new line.

    Happy Fish'ing ;)

    1. Fish developers, correct me if i'm wrong please :)

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/802020 2015-01-24T15:32:40Z 2015-01-24T15:32:40Z 'Google Drive new document bookmark'

    Here's a neat trick: Bookmarks to create all sorts of Google Drive documents. This way you don't have to first access Google Drive and click on new, you can just have the appropriate bookmarks in your browser's toolbar. Just add these links:

    - New Google Document: [https://drive.google.com/document/?action=new](https://drive.google.com/document/?action=new) - New Google Spreadsheet: [https://drive.google.com/spreadsheet/?action=new](https://drive.google.com/spreadsheet/?action=new) - New Google Presentation: [https://drive.google.com/presentation/?action=new](https://drive.google.com/presentation/?action=new)

    Have fun documenting :)

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/802019 2015-01-24T15:31:25Z 2015-01-24T15:31:25Z 'Pure CSS dancing bender'

    I love technology :)

    Found [here](http://liveweave.com/zGYghK).

    Pedro Assunção
    tag:pedroassuncao.com,2013:Post/802018 2015-01-24T15:30:03Z 2015-01-24T15:30:04Z 'You should get Training Time for iOS'

    And why, you might ask? For one because i made it :)

    But seriously, if you are into intense, repetition-based training, you might want to take a look at it. It's an [iOS app](https://itunes.apple.com/us/app/training-time!/id692787267?mt=8) that allows you to set the duration of each repetition, as well as the resting time between reps. Then all you have to do is hit start and listen to the app as it tells you when to rest and when to exercise.

    Because i rarely develop something i don't want for myself, i've been using it for a while, along with a set of 5-6 different exercices, for a total of 7-8 minutes of training everyday and i've found it to be a nice and fast way to be in good general shape. Your mileage may vary but you can always top that with, who knows, a bit of [Kung Fu](https://en.wikipedia.org/wiki/Wong_Shun_Leung) ;)

    Training Time! can be found on the App Store, [here](https://itunes.apple.com/us/app/training-time!/id692787267?mt=8).

    Pedro Assunção