Skip to main content

Making a GIF out of a folder of PNGs (plus resizing)

I need to update the gif from the Event Fabric landing page and I forgot how I did it last time.

So this time I will write it here as a reminder.

First take the screenshots, I do it the good ol' way by using the browser fullscreen and hitting the screeshot key at almost regular intervals.

That leaves me with a set of screenshots I want to resize, so I run:

mogrify -path small -resize 800x450 *.png


This requires imagemagick to be installed

This will resize all the *.png files in the current folder to 800x450 and write the results into a folder called small.

Now we go to the small folder and generate the gif:

cd small
convert -delay 100 -loop 0 *.png animation.gif

This will greate a gif that transitions every second from the png images and save it in the animation.gif file.

Testing erlang ldap lib eldap with local ldap server the easy way

First we need to pick an ldap server to run, I've heard horror stories about setting up ldap servers locally for testing purposes so I was surpised by how easy it was to setup a ldap server using Apache Directory Studio which is a kind of Visual Tool to manage Apache Directory from an Eclipse based UI.

We start by downloading it from the Apache Directory Download Page

After downloading and unpacking it (snippet for the lazy linux users):


tar -xzf ApacheDirectoryStudio-linux-x86_64-2.0.0.v20130628.tar.gz

Now we start it, in my case I had some segfaults as noted on the download page so I had to add the variable declaration before, it works for fedora, you may have to change the path a little:

GTK2_RC_FILES=/usr/share/themes/Raleigh/gtk-2.0/gtkrc ./ApacheDirectoryStudio

Now that we have it running we will see something like this:


We first create a new server by clicking on new server on the bottom left:


We pick "ApacheDS 2.0.0" just because we like to be in the bleeding edge (?):


If we double click the created server we can see the config, I leave everything as default:


We now start the server by clicking the green run button on the bottom left:


Then we want to create a connection, we do that by right clicking the server and selecting "Create a Connection":


Then we connect:


Now we can see the details of the server on the top left panel, we click the entry named "dc=example,dc=com" (in my case, if you changed the config it may be different for you.

on the pop up menu we pick "New -> New Entry":


On the dialog we select "Create entry from scratch" and click next:


We want to create an organization unit to hold our users so we start typing "org" on the "Available object classes" entry until we see the entry "organizationalUnit":


We select it and click the "Add" button, when the right panel is populated we click "Next >"


On the next step of the dialog we enter "ou" on the RDN entry and "users" on the right side and click "Next >"


On the next step we click "Finish"


Now we want to create a new user under our "users" organization unit, to do that we right click ont he users ou and again select "New -> New Entry" and pick "Create entry from scratch" and then "Next >".


after that we look for the object class "inetOrgPerson" and click "Add" and then "Next >":


On the next step we enter uid as RDN and the username as value on the right side, in my case it will be mariano because I'm egocentric :P


Then we click "Next >" and on the next step we fill cn (Common Name) and sn (Surename) and click "Finish"

by the way, dc is Domain Component and dn is Distinguished Name ;)


Now we have our first user but it doesn't have a password, let's set it by double clicking the user on the top left pannel and clicking the "New Attribute" on the bar at the top of the center panel:


On the dialog that opens we pick "Attribute type" "userPassword" and click "Next >"


We enter a password:


And that's it, we have a user with a password inside an organization unit!


Now that we have the server running and one user we can code some erlang to try it.

Most of the code was taken from the Erlang Central Article "How To Talk LDAP from Erlang"

1> Host = "".
2> Port = 10389.
3> {_,S} = eldap:open([Host], [{port, Port}]).
4> UserRest = "ou=users,dc=example,dc=com".
5> Username = "mariano".
6> Password = "secret".
7> DN = "uid=" ++ Username ++ "," ++ UserRest.
8> eldap:simple_bind(S, DN, Password).
9> eldap:simple_bind(S, DN, "anothersecret").

and that's the basics, there's some more code in the article were this code was based.

You can also find the docs for the eldap library in the erlang documentation for eldap

basic TCP echo server with rebar, reltool, ranch and lager

create project skeleton:

mkdir eco
cd eco
chmod u+x rebar
./rebar create-app appid=eco

let's add some dependencies, ranch to accept tcp connections and lager for logging, for that open rebar.config with your text editor and enter this:

{deps, [
    {lager, "2.1.0", {git, "", {tag, "2.1.0"}}},
    {ranch, "1.1.0", {git, "", {tag, "1.1.0"}}}

{erl_opts, [debug_info, {parse_transform, lager_transform}]}.


if you put lager dep after ranch you will get an error when compiling, that's sad

now let's try compiling it:

./rebar get-deps
./rebar compile

we can start our app from the shell, which won't be really useful, but why not:

erl -pa ebin/ deps/*/ebin

and we run:

1> application:start(eco).

now let's use ranch and lager for something, first we create a protocol implementation, open a file called eco_protocol.erl and put the following content in it:



start_link(Ref, Socket, Transport, Opts) ->
    Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]),
    {ok, Pid}.

init(Ref, Socket, Transport, _Opts = []) ->
    ok = ranch:accept_ack(Ref),
    loop(Socket, Transport).

loop(Socket, Transport) ->
    case Transport:recv(Socket, 0, 5000) of
        {ok, Data} ->
            lager:info("echoing ~p", [Data]),
            Transport:send(Socket, Data),
            loop(Socket, Transport);
        _ ->
            ok = Transport:close(Socket)

edit the start function in src/eco_app.erl so it looks like this:

start(_StartType, _StartArgs) ->
    {ok, _} = ranch:start_listener(eco, 1, ranch_tcp, [{port, 1883}],
                                                        eco_protocol, []),

and add the apps we need in by adding ranch and lager to the applications entry like this:

{applications, [

now let's compile and try again:

./rebar compile
Erlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V6.3  (abort with ^G)
1> application:start(eco).
2> application:start(ranch).
3> application:start(eco).
4> application:start(lager).
5> application:start(goldrush).
6> application:start(syntax_tools).
7> application:start(goldrush).
8> application:start(compiler).
9> application:start(goldrush).
10> application:start(lager).
11> 21:05:52.373 [info] Application lager started on node nonode@nohost
11> application:start(eco).
21:06:09.335 [info] Application eco started on node nonode@nohost


user Cloven from reddit noted that instead of starting all the applications by hand in order you could use:


I was sure there was a way to do it since each app specified the dependencies, you can tell from the fact that each app tells you which one it needs before starting, but I didn't know which was the function to call.

thanks to him!

now let's send some data:

telnet localhost 1883

Connected to localhost.
Escape character is '^]'.

(I wrote the first asd, the second is the reply)

in the console you should see this log line:

21:10:05.098 [info] echoing <<"asd\r\n">>

now let's build a release so others can use our server (?):

mkdir rel
cd rel
../rebar create-node nodeid=eco

add the following two lines to rebar.config:

{sub_dirs, ["rel"]}.
{lib_dirs, ["deps"]}.

and edit rel/reltool.config, change the lib_dirs entry to this:

{lib_dirs, ["../deps"]},

add ranch and lager in the rel entry:

{rel, "eco", "1",

and change the app, echo entry to look like this:

{app, eco, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]}

now let's try to build a release:

./rebar compile
./rebar generate

now let's start our server:

./rel/eco/bin/eco console

you should see some output like this:

Erlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

=INFO REPORT==== 5-Feb-2015::22:15:22 ===
inet_parse:"/etc/resolv.conf":4: erroneous line, SKIPPED
21:15:22.393 [info] Application lager started on node 'eco@'
21:15:22.394 [info] Application eco started on node 'eco@'
Eshell V6.3  (abort with ^G)

now let's telnet again:

telnet localhost 1883

Connected to localhost.
Escape character is '^]'.

on the console again you should see some log like this:

21:16:01.540 [info] echoing <<"lala!\r\n">>

and that's it, now evolve your echo server into an actual server :)

How To Setup Vagrant Android/phonegap Build Env

this is a brain dump of something I did and I want documented somewhere.

first install vagrant, I won't go over it.

then do:

vagrant init

then edit the generated Vagrant file, I changed this:

# use ubuntu trusty = "ubuntu/trusty64"

# 1GB or ram
config.vm.provider "virtualbox" do |vb|
    vb.memory = "1024"

# provision all the needed packages, I'm using it to build a phonegap app
# that's why I install all the npm stuff
config.vm.provision "shell", inline: <<-SHELL
  sudo apt-get update
  sudo apt-get install -y ant lib32ncurses5 lib32stdc++6 lib32z1 npm build-essential git nodejs-legacy openjdk-7-jdk
  sudo npm install -g "phonegap@3.5.0-0.21.14" bower grunt-cli


vagrant up
vagrant ssh

inside the vm:

tar -xzf android-sdk_r24.0.2-linux.tgz

echo "export PATH=\$PATH:\$HOME/android-sdk-linux/tools:\$HOME/android-sdk-linux/platform-tools:\$HOME/android-sdk-linux/build-tools/19.1.0" >> $HOME/.bashrc

android update sdk -a --no-ui --filter "platform-tools"
android update sdk -a --no-ui --filter "android-19"
android update sdk -a --no-ui --filter "sys-img-armeabi-v7a-android-19"
android update sdk -a --no-ui --filter "build-tools-19.1.0"
android create avd --name myandroid -t "android-19"

I installed the version 19 of the sdk because of project requirements, feel free to install something more up to date, to see what you can install you can run:

android list sdk --extended

Youtube Video to Audio Download

this is a reminder for myself in the future, I tend to watch/listen to talks when I'm doing something like cooking, cleaning.

but when I'm outside I want to take my music player and the talks tend to be on youtube, so normally I search for "youtube to mp3" and there's some ad ridden site that does that (sometimes)

but today I wanted to learn how to do it from the cli and here is the post that explains it so I can come back int he future to copy paste the commands.

first install youtube-dl and ffmpeg:

sudo yum install youtube-dl ffmpeg

then download your video:


then extract the audio from the video:

ffmpeg -i Music\ Theory\ and\ Performance\ Analysis\ with\ Sebastian\ and\ Czerny-06h21nBqwec.webm -strict experimental -acodec vorbis -ab 128k -vn ./output.ogg

then do whatever you want with the video and the audio

Overtone, clojure, jackd, alsa in ubuntu 14.10

ok, this is a small dump of what I did, I'm surely missing some stuff and surely it won't work as is for you, but maybe it does and you are as happy as I'm right now generating noise (not as happy as anyone close to me at this moment).

all the things I think I installed:

sudo apt install alsa-tools alsaplayer-jack alsa-utils pulseaudio-module-jack supercollider jack-tools fftw3 qjackctl openjdk-8-jdk

yes, you can see the desperation there with some stuff that may not make sense, but at least it works..

you need to install leiningen, it's really easy and it has good instructions on the site so I won't go into details, just follow the instructions here:

then I follow the instructions from overtone's wiki here:

before starting our repl and rocking like a hurricane we need to kill pulseaudio and start jack, it sounds easier than it is because pulseaudio just won't stay dead :(

the way I found to make it work was to edit pulseadio client.conf:

sudo vim /etc/pulse/client.conf

uncomment the line (remove the semicolon):

; autospawn = yes

and leaving it like this:

autospawn = no

I added myself to the audio group, not sure if it's required but just in case:

sudo adduser $USER audio

for this to take effect you need to logout and login again, to make sure you have the group, open a terminal and run:


you should see audio between some other groups, if you can't see it try rebooting or replacing $USER with your actual username in the adduser command.

now stop pulseaudio:

pulseaudio --kill

then start jackd, I tried all the combinations I could find on the internet without success, this is the one that worked for me:

jackd -R -d alsa -d hw:1

if that doesn't work try:

jackd -R -d alsa

or try the versions that are recommended on the overtone wiki:

jackd -r -d alsa -r 44100


jackd -r -d alsa -r 44100 -P

you can also try running qjackctl and play with the settings to see if you have luck.

now that we (hopefully) have jackd running, we can start playing with overtone, here is a small dump of a session:

lein new tutorial
cd tutorial

# add [overtone "0.9.1"] to :dependencies
vim project.clj

lein deps
lein repl

# inside the clojure repl
user=> (use '
user=> (definst foo [] (saw 220))
#<instrument: foo>
user=> (foo)
#<synth-node[loading]: user/foo 35>
user=> (kill 35)

when you are done you can stop jackd from the ui or from the shell however you started it and start again pulseaudio:

pulseaudio --start

some additional note, when I'm using jackd I can't set the volume from the media keys or the sound mixer in the top planel, I run:


press F6, select the output I'm using and change it with the keys (ESC to close).

hope it's useful for someone.

Making a Chat App with Erlang, Rebar, Cowboy and Bullet

this is a continuation of the post about erlang, cowboy and rebar.

let' start by adding the bullet dep:

{sub_dirs, ["rel"]}.

{deps, [
    {cowboy, "1.0.0", {git, "", {tag, "1.0.0"}}},
    {bullet, "0.4.1", {git, "", {tag, "0.4.1"}}}

now get the deps:

./rebar get-deps

add bullet as a dependency on

{application, disrupt,
  {description, ""},
  {vsn, "1"},
  {registered, []},
  {applications, [
  {mod, { disrupt_app, []}},
  {env, []}

register our bullet handler with cowboy:

start(_StartType, _StartArgs) ->
    {ok, ChannelPid} = disrupt_channel:new(),
    Dispatch = cowboy_router:compile([
        {'_', [
               {"/chat", bullet_handler, [{handler, disrupt_chat_handler}, {channel, ChannelPid}]},
               {"/ui/[...]", cowboy_static, {priv_dir, disrupt, "assets",
                                             [{mimetypes, cow_mimetypes, all}]}}
    {ok, _} = cowboy:start_http(http, 100, [{port, 8080}], [
        {env, [{dispatch, Dispatch}]}

the important lines are:

{ok, ChannelPid} = disrupt_channel:new(),

were we create a new chat channel that will be passed to all disrupt_chat_handler instances here:

{"/chat", bullet_handler, [{handler, disrupt_chat_handler}, {channel, ChannelPid}]},

also note that I changed the path of the ui to /ui/... instead of it being at the root.

add the js libs we need to use bullet (yes, I could use bower, but let's keep it simple):

mkdir priv/assets/vendor
mkdir priv/assets/js
cp deps/bullet/priv/bullet.js priv/assets/vendor
wget -O priv/assets/vendor/jquery.js

we create a really simple chat page at index.html:

<!doctype html>
  <meta charset="utf-8">
  <script src="vendor/jquery.js"></script>
  <script src="vendor/bullet.js"></script>
  <script src="js/app.js"></script>
   body{ font-family: helvetica; color: #333; background-color: #fefefe;
    margin-left: 25%; width: 50%; }
   p, textarea{ padding: 0; }
   p, button, textarea{ width: 100%; margin: 1em 0; }
   label{ float: left; width: 45%; }
   input{ width: 50%; float: right; }
   input, textarea{ border: 1px solid #ddd; }
  <label for="input">Nickname</label>
  <input type="text" id="nick" value="anonymous"/>
  <textarea id="output" cols="80" rows="25"></textarea>
  <label for="input">Input</label>
  <input type="text" id="input"/>
  <button id="send">Send</button>

add code to handle the chat app on priv/assets/js/app.js:

/*globals $, document, window*/
function disruptApp(document, window, $) {
    'use strict';
    var input = document.getElementById('input'),
        output = document.getElementById('output'),
        nickInput = document.getElementById('nick'),
        send = document.getElementById('send'),


    function sendMessage(text) {
        var nick = getNick();
        connection.send(nick + ': ' + text);

    function onSendClicked() {
        var text = input.value.trim();

        if (text !== '') {

        input.value = '';

    function getNick() {
        var nick = nickInput.value.trim();

        if (nick === '') {
            return 'anonymous';
        } else {
            return nick;

    function notify(text) {
        var date = (new Date()).toLocaleString();
        output.innerHTML = output.innerHTML + '[' + date + '] ' + text + '\n';

    function onData(data) {

    send.addEventListener('click', onSendClicked);

    function start(url, options, notify, onData) {
        var connection = $.bullet(url, options);

        connection.onopen = function(){

        connection.onclose = connection.ondisconnect = function(){

        connection.onmessage = function(e){
            if ( === 'pong'){
            } else {

        connection.onheartbeat = function(){

        return connection;

    connection = start('ws://localhost:8080/chat', {}, notify, onData);

document.addEventListener("DOMContentLoaded", function() {
    'use strict';
    disruptApp(document, window, $);

we need a simple pubsub mechanism for channels, I won't explain it here in detail but you can read about erlang's gen_event behaviour which is the one that does all the work:


-export([new/0, subscribe/2, unsubscribe/2, send/2]).

-export([init/1, handle_event/2, handle_call/2, handle_info/2, code_change/3,
%% API

new() -> gen_event:start_link().

subscribe(Channel, Pid) ->
    gen_event:add_handler(Channel, {disrupt_channel, Pid}, [Pid]).

unsubscribe(Channel, Pid) ->
    gen_event:delete_handler(Channel, {disrupt_channel, Pid}, [Pid]).

send(Channel, Event) ->
    gen_event:notify(Channel, Event).

-record(state, {pid}).
%% callbacks
init([Pid]) -> {ok, #state{pid=Pid}}.

handle_event(Msg, State=#state{pid=Pid}) ->
    Pid ! Msg,
    {ok, State}.

handle_call(_, State) -> {ok, ok, State}.

handle_info(_, State) -> {ok, State}.

code_change(_OldVsn, State, _Extra) -> {ok, State}.

terminate(_Reason, _State) -> ok.

the important part from the code above is the fact that we store the pid of the bullet handler on the gen_event instance so we can send the message back when we get notified:

handle_event(Msg, State=#state{pid=Pid}) ->
    Pid ! Msg,
    {ok, State}.

the bullet handler for the chat channel is:


-export([init/4, stream/3, info/3, terminate/2]).

-record(state, {channel}).

init(_Transport, Req, Opts, _Active) ->
    io:format("channel init ~p~n", [Opts]),
    {channel, ChannelPid} = lists:keyfind(channel, 1, Opts),
    disrupt_channel:subscribe(ChannelPid, self()),
    {ok, Req, #state{channel=ChannelPid}}.

stream(<<"ping">>, Req, State) ->
    io:format("ping received~n"),
    {reply, <<"pong">>, Req, State};

stream(Data, Req, State=#state{channel=ChannelPid}) ->
    io:format("message received ~s~n", [Data]),
    disrupt_channel:send(ChannelPid, {msg, self(), Data}),
    {ok, Req, State}.

info({msg, _Sender, Data}, Req, State) ->
    io:format("msg received ~p~n", [Data]),
    {reply, Data, Req, State}.

terminate(_Req, #state{channel=ChannelPid}) ->
    io:format("unsubscribing from channel~n"),
    disrupt_channel:unsubscribe(ChannelPid, self()),

we subscribe on init, unsubscribe on terminate, when we receive a ping message we reply it only to the sender with pong, if we receive something else we send the message to the channel so it gets sent to all subscribers, that get the message on the info function where they send it to the browsers.


rm -rf rel/disrupt && ./rebar compile generate


./rel/disrupt/bin/disrupt console

open http://localhost:8080/ui/index.html in two or more browsers and chat!


Serving Static Files with Erlang, Cowboy and Rebar, (raw material)

the "serving static files from a server" market needs some disruption, let's tackle that problem with some erlang.

create the folder:

mkdir disrupt
cd disrupt

get rebar:

chmod u+x rebar

generate app:

./rebar create-app appid=disrupt

add dependencies:

vim rebar.config

the file should contain the following code:

{deps, [
    {cowboy, "1.0.0", {git, "", {tag, "1.0.0"}}}

this tells to get cowboy 1.0.0 from git as dependency, let's fetch the dependencies:

./rebar get-deps

now let's serve some static files, open src/disrupt_app.erl, change the start function so it looks like this:

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        {'_', [
            {"/[...]", cowboy_static, {priv_dir, disrupt, "assets",
                [{mimetypes, cow_mimetypes, all}]}}
    {ok, _} = cowboy:start_http(http, 100, [{port, 8080}], [
        {env, [{dispatch, Dispatch}]}

the code above is taken from the static example from cowboy adapted to our needs:

docs here:

now make the priv/assets folder:

mkdir -p priv/assets

and put some content in the index file:

echo "hello static world" > priv/assets/index.html

let's make a release for the project, first create the release files:

mkdir rel
cd rel
../rebar create-node nodeid=disrupt
cd ..

edit rel/reltool.config, the line:

{lib_dirs, []},

should change to:

{lib_dirs, ["../deps"]},

add the line:

sub_dirs, ["rel"]}.

to the top of the rebar.config file

if not you get this error:

Command 'generate' not understood or not applicable

yay helpfulness!

now we are one confusing error closer to our goal, but now we get:

ERROR: generate failed while processing /home/mariano/tmp/disrupt/rel: {'EXIT',{{badmatch,{error,"disrupt: Missing application directory."}},

only because I've seen some other erlang projects I decided that this may be the solution:

mkdir -p apps/disrupt
cd apps/disrupt
ln -s ../../src
ln -s ../../ebin
ln -s ../../priv
cd ../..

we try again to make the release and we get the error again, nice!

for no apparent reason that the fact that I saw it on some other project, change the line on rel/reltool.config:

{lib_dirs, ["../deps"]},


{lib_dirs, ["../deps", "../apps"]},

trying again:

./rebar compile generate


let's try running it:

./rel/disrupt/bin/disrupt console

and what do we get? well, a crash! \o/:

Exec: /home/mariano/tmp/disrupt/rel/disrupt/erts-5.10.4/bin/erlexec -boot /home/mariano/tmp/disrupt/rel/disrupt/releases/1/disrupt -mode embedded -config /home/mariano/tmp/disrupt/rel/disrupt/releases/1/sys.config -args_file /home/mariano/tmp/disrupt/rel/disrupt/releases/1/vm.args -- console
Root: /home/mariano/tmp/disrupt/rel/disrupt
Erlang R16B03 (erts-5.10.4) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V5.10.4  (abort with ^G)
=INFO REPORT==== 29-Aug-2014::11:49:32 ===
    application: disrupt
    exited: {bad_return,
    type: permanent
{"Kernel pid terminated",application_controller,"{application_start_failure,disrupt,{bad_return,{{disrupt_app,start,[normal,[]]},{'EXIT',{undef,[{cowboy_router,compile,[[{'_',[{\"/[...]\",cowboy_static,{priv_dir,disrupt,\"assets\",[{mimetypes,cow_mimetypes,all}]}}]}]],[]},{disrupt_app,start,2,[{file,\"src/disrupt_app.erl\"},{line,13}]},{application_master,start_it_old,4,[{file,\"application_master.erl\"},{line,269}]}]}}}}}"}

Crash dump was written to: erl_crash.dump
Kernel pid terminated (application_controller) ({application_start_failure,disrupt,{bad_return,{{disrupt_app,start,[normal,[]]},{'EXIT',{undef,[{cowboy_router,compile,[[{'_',[{"/[...]",cowboy_static

with all my time reading erlang crashes I see an undef there, it seems the app cant find cowboy_router:compile

but I have it on my deps..

well, let's put it on src/ applications for no other reason that I've seen people do that, the file should look like this:

{application, disrupt,
  {description, ""},
  {vsn, "1"},
  {registered, []},
  {applications, [
  {mod, { disrupt_app, []}},
  {env, []}

see the cowboy as last element on the applications list? that's what you should add.

let's try again:

./rebar compile generate

and I get:

<some output removed here>

==> rel (generate)
ERROR: generate failed while processing /home/mariano/tmp/disrupt/rel: {'EXIT',{{badmatch,{error,"Application cowboy is used in release \"disrupt\" and cannot be excluded"}},

"Application cowboy is used in release "disrupt" and cannot be excluded"

who told you to exclude it?

let's apply a technic we already used a lot before, let's make up reasons for what it may be failing, it says exclude there and I've seen a lot of exclude and include atoms in rel/reltool.config, maybe it's that?

let's layer some other technic I use a lot, let's try to make that file look as similar as another one I've seen that works, in this case it's the reltool.config file generated by riak_core rebar template:

ok, that one seems to have less stuff than ours, let's start commenting everything that looks different until we reach this point:

{sys, [
    {lib_dirs, ["../deps", "../apps"]},
        %{erts, [{mod_cond, derived}, {app_file, strip}]},
        %{app_file, strip},
        {rel, "disrupt", "1",
        {rel, "start_clean", "",
        {boot_rel, "disrupt"},
        {profile, embedded},
        %{incl_cond, exclude},
        {excl_archive_filters, [".*"]}, %% Do not archive built libs
    {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
        {excl_app_filters, ["\.gitignore"]},
        {app, sasl,   [{incl_cond, include}]},
        %{app, stdlib, [{incl_cond, include}]},
        %{app, kernel, [{incl_cond, include}]},
        {app, disrupt, [{incl_cond, include}]}

{target_dir, "disrupt"}.

{overlay, [
    {mkdir, "log/sasl"},
        {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
        {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
        {copy, "files/disrupt", "bin/disrupt"},
        {copy, "files/disrupt.cmd", "bin/disrupt.cmd"},
        {copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
        {copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
        {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
        {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}

trying again:

rm -rf rel/disrupt
./rebar compile generate


now let's try running it:

./rel/disrupt/bin/disrupt console

the output we get:

Exec: /home/mariano/tmp/disrupt/rel/disrupt/erts-5.10.4/bin/erlexec -boot /home/mariano/tmp/disrupt/rel/disrupt/releases/1/disrupt -mode embedded -config /home/mariano/tmp/disrupt/rel/disrupt/releases/1/sys.config -args_file /home/mariano/tmp/disrupt/rel/disrupt/releases/1/vm.args -- console
Root: /home/mariano/tmp/disrupt/rel/disrupt
Erlang R16B03 (erts-5.10.4) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V5.10.4  (abort with ^G)

that's what I would call a non crashing system, let's see if it works:

curl http://localhost:8080/index.html

we get:

hello static world


and that's how you serve a static file with erlang, cowboy and rebar :)

How To Build Twister Distributed Microblog on Ubuntu 13.10 (Saucy)

today I found out about twisterd and I wanted to give it a try (and reserve my username ;) so I tried and it took a while to get all the dependencies right, to avoid you the pain here is the guide.

take into account the comments in the script.

just a console dump, it should work just by pasting the commands in order:

mkdir twister
cd twister
sudo apt-get update
sudo apt-get install libssl-dev libdb-dev libdb++-dev libminiupnpc-dev libboost-all-dev build-essential git autoconf libtool
git clone
git clone
mkdir ~/.twister
mv twister-html ~/.twister/html
cd twister-core/libtorrent

# NOTE: the following command will fail with an error about boost, ignore
# it and run the following commands

./configure --enable-logging --enable-debug --enable-dht --with-boost-libdir=/usr/lib/x86_64-linux-gnu/
cd ../src
make -f makefile.unix
./twisterd -daemon -rpcuser=user -rpcpassword=pwd -rpcallowip=

BTW I'm @mariano :)

Install Immutant 1.0 full as a service on debian/ubuntu

Small dump with instructions to install immutant as a service on debian, ubuntu or derivatives.

I adapted the init script that comes with immutant to work on debian:

# install needed packages
sudo apt-get install wget unzip openjdk-7-jdk daemon

# create a dir to download files
mkdir ~/soft
cd ~/soft

# download immutant 1.0 full


# create user that will run the service
sudo adduser jboss-as

# create required folders
sudo cp -r immutant-1.0.0-full/jboss /usr/share/jboss-as/
sudo mkdir -p /var/log/jboss-as /var/run/jboss-as/

# set permissions
sudo chown -R jboss-as.jboss-as /var/log/jboss-as /var/run/jboss-as /usr/share/jboss-as/

# get and install init.d script
sudo wget -O /etc/init.d/jboss-as-standalone
sudo chmod u+x /etc/init.d/jboss-as-standalone

# register the service
update-rc.d jboss-as-standalone default

# start it
sudo /etc/init.d/jboss-as-standalone start