with devcards how to

Simple step by step guide to try with devcards.

This assumes you have leiningen installed if not, go to and follow the instructions there.

Let's start by creating the basic devcards environment using the devcards template:

lein new devcards omnom
cd omnom
lein figwheel

The output should look something like this:

Figwheel: Starting server at http://localhost:3449
Focusing on build ids: devcards
Compiling "resources/public/js/compiled/omnom_devcards.js" from ["src"]...
Successfully compiled "resources/public/js/compiled/omnom_devcards.js" in 15.476 seconds.
Started Figwheel autobuilder

Launching ClojureScript REPL for build: devcards
Figwheel Controls:


  Switch REPL build focus:
          :cljs/quit                      ;; allows you to switch REPL to another build
    Docs: (doc function-name-here)
    Exit: Control+C or :cljs/quit
 Results: Stored in vars *1, *2, *3, *e holds last exception object
Prompt will show when figwheel connects to your application
To quit, type: :cljs/quit

then after it does all it's thing open http://localhost:3449/cards.html

it should look something like this:


click the omnom.core link, you should see this:


now we have to install the latest development snapshot for om to try, in some folder outside your project run:

git clone
cd om
lein install

Now let's add the dependencies to our project, open project.clj and make the :dependencies section look like this:

:dependencies [[org.clojure/clojure "1.7.0"]
               [org.clojure/clojurescript "1.7.122"]
               [devcards "0.2.0-3"]
               [sablono "0.3.4"]
               [org.omcljs/om "0.9.0-SNAPSHOT"]
               [datascript "0.13.1"]]

Now restart fighwheel (press Ctrl + d) and run it again:

lein figwheel

reload the page.

open the file src/omnom/core.cljs and replace its content with this:

(ns omnom.core
   [cljs.test :refer-macros [is async]]
   [goog.dom :as gdom]
   [ :as om :refer-macros [defui]]
   [om.dom :as dom]
   [datascript.core :as d]
   [sablono.core :as sab :include-macros true])
   [devcards.core :as dc :refer [defcard deftest]]))


(defcard first-card
  (sab/html [:div
             [:h1 "This is your first devcard!"]]))

(defui Hello
  (render [this]
    (dom/p nil (-> this om/props :text))))

(def hello (om/factory Hello))

(defcard simple-component
  "Test that Om Next component work as regular React components."
  (hello {:text "Hello, world!"}))

(def p
    {:read   (fn [_ _ _] {:quote true})
     :mutate (fn [_ _ _] {:quote true})}))

(def r
    {:parser p
     :ui->ref (fn [c] (-> c om/props :id))}))

(defui Binder
  (componentDidMount [this]
    (let [indexes @(get-in (-> this om/props :reconciler) [:config :indexer])]
      (om/update-state! this assoc :indexes indexes)))
  (render [this]
    (binding [om/*reconciler* (-> this om/props :reconciler)]
      (apply dom/div nil
        (hello {:id 0 :text "Goodbye, world!"})
        (when-let [indexes (get-in (om/get-state this)
                             [:indexes :ref->components])]
          [(dom/p nil (pr-str indexes))])))))

(def binder (om/factory Binder))

(defcard basic-nested-component
  "Test that component nesting works"
  (binder {:reconciler r}))

(deftest test-indexer
  "Test indexer"
  (let [idxr (get-in r [:config :indexer])]
    (is (not (nil? idxr)) "Indexer is not nil in the reconciler")
    (is (not (nil? @idxr)) "Indexer is IDeref")))

(defn main []
  ;; conditionally start the app based on wether the #main-app-area
  ;; node is on the page
  (if-let [node (.getElementById js/document "main-app-area")]
    (js/React.render (sab/html [:div "This is working"]) node)))


;; remember to run lein figwheel and then browse to
;; http://localhost:3449/cards.html

it should display the om cards if not try reloading the page.

now just keep adding cards!

Quotes N+1

Some Quotes I had around and wanted to put somewhere.

Navigation implies state. Software that can be navigated is software in which the user can get lost. The more navigation, the more corners to get stuck in. The more manipulable state, the more ways to wander into a “bad mode.” State is the primary reason people fear computers—stateful things can be broken
Most of the time, a person sits down at her personal computer not to create, but to read, observe, study, explore, make cognitive connections, and ultimately come to an understanding. This person is not seeking to make her mark upon the world, but to rearrange her own neurons. The computer becomes a medium for asking questions, making comparisons, and drawing conclusions—that is, for learning.
Many types of context can be naturally expressed in some informative graphical domain, relieving the user from manipulating information-free general-purpose controls.
If the software properly infers as much as possible from history and the environment, it should be able to produce at least a reasonable starting point for the context model. Most of the user’s interaction will then consist of correcting (or confirming) the software’s predictions. This is generally less stressful than constructing the entire context from scratch.
Simplicity. “I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is make it so complicated that there are no obvious deficiencies.” C.A.R. Hoare, The Emperor’s Old Clothes Turing Award lecture (1980), p81. From a practical (and historical) standpoint, we can assume that no complex specification will be implemented exactly. This, in itself, is not a problem. However, multiple, decentralized implementations of a complex specification will be incorrect in different ways. A platform consisting of the union of all possible implementations is thus arbitrarily unreliable—the designer can have no assurance of what a recipient actually receives. For a platform to be reliable, it must either have a single implementation, or be so utterly simple that it can be implemented uniformly. If we assume a practical need for open, freely implementable standards, the only option is simplicity.*

All of our days are numbered, we cannot afford to be idle To act on a bad idea is better than to not act at all. Because the worth of an idea never becomes apparent until you do it.

—nick cave, 20000 days on earth

Forward syslog messages to flume with rsyslog

As usual, brain dump, just instructions, not much content.

download flume from here:

I'm using this one:

unpack and put it somewhere.

create a file with the following content, I will name it flume-syslog.conf and place it in ~/tmp/, you should too if you are lazy and don't want to change the commands:

# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1

# I'll be using TCP based Syslog source
a1.sources.r1.type = syslogtcp
# the port that Flume Syslog source will listen on
a1.sources.r1.port = 7077
# the hostname that Flume Syslog source will be running on = localhost

# Describe the sink
a1.sinks.k1.type = logger

# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

# Bind the source and sink to the channel
a1.sources.r1.channels = c1 = c1

Install rsyslog if you don't have it and start it, I'm using fedora 22, change for your distro:

sudo dnf install rsyslog
sudo service rsyslog start


For Fedora Users

I had to disable selinux since it was blocking some ports, YMMV

Configure rsyslog with your rule, you can do it directly on /etc/rsyslog.conf or better, check that the following line is uncommented:

$IncludeConfig /etc/rsyslog.d/*.conf

And put your config under /etc/rsyslog.d/50-default.conf (create it if it doesn't exist)

We are going to forward only messages with a given tag, since we are interested on a subset of the logs, in this case we only want log lines with the tag "test", add this to the rsyslog config file:

:syslogtag, isequal, "test:" @@

Save and restart rsyslog:

sudo service rsyslog start

Start flume with your configuration:

./bin/flume-ng agent --conf conf --conf-file ~/tmp/flume-syslog.conf --name a1 -Dflume.root.logger=INFO,console  -Dorg.apache.flume.lifecycle.LifecycleSuperviso=INFO,console


You should run the flume-ng command from the flume folder otherwise a log4j warning will appear and you won't see the output of the sink

Now generate a log line with our tag:

logger -t test 'Testing Flume with Syslog!

you should see a line like this:

2015-08-27 18:06:25,096 (SinkRunner-PollingRunner-DefaultSinkProcessor) [INFO - org.apache.flume.sink.LoggerSink.process(] Event: { headers:{host=ganesha, Severity=5, Facility=1, priority=13, timestamp=1440695180000} body: 74 65 73 74 3A 20 54 65 73 74 69 6E 67 20 46 6C test: Testing Fl }

If you don't see the line check /var/log/messages to see if your message is there:

sudo vim /var/log/messages

Bonus track! sending apache logs to syslog and from there to flume.

for this install apache 2, on fedora:

sudo dnf install httpd
sudo service httpd start
sudo bash -c "echo 'welcome!' > /var/www/html/index.html"

curl localhost

The output should be:


Now configure apache to forward logs to syslog, open /etc/httpd/conf.d/welcome.conf and add at the bottom:

CustomLog "|/usr/bin/logger -t test" combined

Restar apache:

sudo service httpd restart

Now open the page or use curl to get a page:


You should see a new log on flume.

Where to go from here?

  • Put flume on another machine, change the ip address to that address
  • change the tag (test) on rsyslog and on welcome.conf to something else
  • Buy me a beer

Enabling CORS in Solr in a Cloudera environment

This is a continuation of this post: Enable CORS in Apache Solr but this time for an instance that is running in cloudera.

No idea how it was installed since it was already there, but doing some investigation and avoiding reading the docs at all costs I arrived at this solution.

The idea of this post is to make you avoid reading the docs too!

First I will give names to some things that may be different for you:


Now do:

cd $CDH/jars/

cd $CDH/lib/bigtop-tomcat/lib/
ln -s $CDH/jars/jetty-servlets-9.1.5.v20140505.jar
ln -s $CDH/jars/jetty-util-9.1.5.v20140505.jar

chown $CDH_USER.$CDH_GROUP jetty-servlets-9.1.5.v20140505.jar
chown -h $CDH_USER.$CDH_GROUP jetty-servlets-9.1.5.v20140505.jar

chown $CDH_USER.$CDH_GROUP jetty-util-9.1.5.v20140505.jar
chown -h $CDH_USER.$CDH_GROUP jetty-util-9.1.5.v20140505.jar

Then create $CDH/lib/bigtop-tomcat/bin/ with your favorite text editor and put in it the following:


Open $CDH/etc/solr/tomcat-conf.dist/WEB-INF/web.xml with your text editor and follow the instructions at Enable CORS in Apache Solr

The way to know if it worked is to open the Solr admin panel, if it loads it works, if it doesn't look at the logs, mine are at /var/log/solr/. To be sure that the classpath was set correctly from look in the solr admin page in the "Java Properties" section for the java.class.path variable, it should have the class path you set in setenv.hs plus some extra stuff (mainly bootstrap.jar).

If the admin page doesn't load (tomcat 404) look at the logs, some class loading error may be happening, comment the config you added in web.xml and restart.

The version I'm using of the jetty jars is because newer versions are compiled for java 1.8 and I have 1.7, use older/newer depending on your java version.

Enable CORS in Apache Solr

Quick post since there's no easy googlable (?) resource to do this.

open the file server/solr-webapp/webapp/WEB-INF/web.xml and add the following XML before the existing filter section:

         <param-value>origin, content-type, cache-control, accept, options, authorization, x-requested-with</param-value>


taken from this Stack Overflow response

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