Engineering

I'm working on a new pet project - called Risk... in the browser. Yes, I know, there are game portals out there which have it, and it has been done before. I just want to do it for myself, seems like a massive, but fun, project.

I found a great post on making a map, and it is definitely something I'll check out for the design phase of the project. I've started designing the JavaScript part of the application though, and along the way I thought I'd post about object oriented JavaScript and inheritance.

On his site, Crockford describes JavaScript as "... a class-free, object-oriented language, and as such, it uses prototypal inheritance instead of classical inheritance" - no better way to say it. So what does this mean for me when I'm designing a Risk game?

One example is in the design for the military. In classical Risk, we have 3 types of military units: infantry, cavalry, and artillery. In my initial design, I had them as a JSON object:

'armyUnits': {
  	'Infantry': 1,
  	'Cavalry': 5,
  	'Artillery': 10,
  },

My thought was to iterate over them, using the key/value pairs to create the pieces on the board, adding methods to the instances created. This will turn into soup. This structure actually lends itself to an inheritance-based model. So let's take a look at how that could be built.

First, we need a parent 'class'. Again, no real classes in JavaScript, just functions, so we can start with something basic like this:

var military = function() {
}

var unit = new military();

console.log(unit, typeof unit)
•> military {} "object"

Great, so now we have the parent class, and you can see we have instantiated it with the keyword 'new', and created an object from it. This is cool and all, but not very useful yet. Now we need to think about what attributes all of these units will share and can be inherited, and which attributes will be unit-specific, and providing private methods to get and set those.

So let's take movement, strength, color, and unitName for our attributes. Of these, probably only movement can be inherited, while the others are unit-specific. Additionally, we probably want one of the three to be the default, if no options are passed to the class at instantiation. Knowing all this, if we take another pass at our parent class, it might look something like this:

var military = function(uName) {
  //unit name - artillery, cavalry or infantry
  this.unitName = uName == undefined ? 'Infantry' : uName.toString(),
  this.movement = 1,
  this.color = 'gray',
  this.strength = 1;

}

Great, so now we can define a new unit and it's slightly more meaningful:

var a = new military();

console.log(a, a.strength);
military {unitName: "Infantry", movement: 1, color: "gray", strength: 1} 1
var b = new military('cavalry');
console.log(b, b.strength);
military {unitName: "cavalry", movement: 1, color: "gray", strength: 1} 1

So you can see we already have a problem. All of our units are inheriting, but they're inheriting everything the same, which is not what we want. A cavalry unit has a strength of 5, so let's fix that.

var military = function(uName) {

this.unitName = uName == undefined ? 'Infantry' : uName.toString(),
this.movement = 1,
this.color = 'gray',
this.strength = 1,
this.getStrength = function() {
  return this.strength;
  },
this.setStrength = function() {
  if(this.unitName == 'Cavalry'){
    return this.strength = 5;
  }
  else if(this.unitName == 'Artillery'){
    return this.strength = 10;
  }
  else {
    return this.strength;
  }
};


}

Right, now we have getter/setters for the strength attributes, and it's conditional based on the name of the unit we pass into the class. This all looks to be good, so now let's take a look at the inheritance piece.

We'll create unit-specific classes - like 'cavalry', and then there are a couple of ways to enable the inheritance. We can use apply(), which takes an array of arguments

var cavalry = function() {
  military.apply(this, ['Cavalry']);
}
var c = new cavalry();
console.log(c, typeof c);
•> cavalry {unitName: "Cavalry", movement: 1, color: "gray", strength: 5} "object"

Awesome! We have created a new military unit, of the type 'cavalry'. Notice our strength is 5, which is what we wanted for that type. Another way we can inherit from military is to use call(), probably better in our case, as it accepts a comma-separated list of strings for the arguments. That looks something like this:

var cavalry = function() {
  military.call(this, 'Cavalry'); //we can add additional args here, ', 'Bob', 'bail of hay', etc..' and it won't affect our class at present. they will just be lost
  this.strength = this.setStrength();
}
var c = new cavalry();
console.log(c, typeof c);
•> cavalry {unitName: "Cavalry", movement: 1, color: "gray", strength: 5}color: "gray"getStrength: ()movement: 1setStrength: ()strength: 5unitName: "Cavalry"__proto__: cavalry "object"

So that's fine too. We have a cavalry unit with a strength of 5. So probably the last thing we will want to do is create some instances of these classes and then have the ability to extend them. If I have the need to add a 'hungry' variable into the cavalry class for example, I want to be able to do so once and have it apply to all instances I've created.

So let's take a look at that.

var horse = new cavalry();
var superHorse = new cavalry();
// now to extend
superHorse.isHungry = function() { console.log('wheres my food?'); }
// call it
superHorse.isHungry();
•> wheres my food?

//call it
horse.isHungry();
Uncaught TypeError: horse.isHungry is not a function(…)

So that did and didn't work. It worked for the one object - superHorse, because isHungry() is only acting as a property added to a specific object (kind of a static method), rather than it being an extension of the cavalry constructor, so it could apply to all instances. So let's make that happen, with a simple change.

cavalry.prototype.isHungry = function() { console.log('I am HUUUUNGRY!'); }

And voila! By applying it to the prototype, it's now accessible to all instances, so let's see what happened to horse and superHorse:

horse.isHungry()
•> I am HUUUUNGRY!

superHorse.isHungry()
•> wheres my food?

Oooh, interesting, so horse object correctly received the method, but superHorse still shows the previous message. That's because it was previously applied as a method to superHorse, so the 'child' method is overriding the 'parent'. But if we look at the __proto__ property for it, we can see the constructor method in action:

superHorse.__proto__.isHungry()
•> I am HUUUUNGRY!

Speaking of hunger, I'm off to lunch, and then on to more of Risk.

 

 

 

So I've been playing around with lambdas a bit lately - brushing up on closures is always fun. Ruby has.. several ways of implementing closures: you've got blocks, procs, lambdas, and methods. They're all of a similar flavor, but have subtle differences.

I found a great article by Erik Trautman and inspired me to play a bit with lambdas, so I wrote a simple test method in Rails console:

def my_func(n)
  puts n
  lambda do |w|
     puts w
     return w
   end
end

 

One of the cool things about lambdas is the return only returns from the lambda, not the outer method. So this means you can do something like this:

my_func('whoa!')
whoa!
 => #<Proc:0x007fdf6c231178@(irb):34 (lambda)>

And as you can see, the method puts the string passed to it, but what's returned is a Proc object - our lambda. It's basically sitting there, waiting for someone to call it and pass it an argument. This is pretty cool, and extremely powerful.

So let's try that - it looks something like this:

my_func('holy').call('smokes')
holy
smokes
 => "smokes" 

Now if we assign this to a variable, we can pull the same thing, pass some data to the variable and have it call our lambda, though this method isn't very useful. Notice that after the call() executes however, it returns a string, not the Proc object.

So let's consider a different example - also not extremely practical, but begins to show the flexibility and power lambdas give you.

Let's say we have a Rabbitt class, and we've created a couple of rabbitts (because..why not?). So if we think about querying for rabbitts, we can do something like this

def get_rabbits
  @rabbitts = Rabbitt.try(:all) rescue nil
end

So now, get_rabbits is going to give us back however many active record objects there are in the Rabbitt.all collection:

get_rabbits
  Rabbitt Load (0.2ms)  SELECT "rabbitts".* FROM "rabbitts"
 => #<ActiveRecord::Relation [#<Rabbitt id: 1, name: "Brier Sr.", color: "dark gray", language: "High Bunny", speed: 74, created_at: "2016-02-23 02:00:29", updated_at: "2016-02-23 02:01:03">, #<Rabbitt id: 2, name: "Teddy", color: "blue", language: "English", speed: 674, created_at: "2016-02-26 01:58:23", updated_at: "2016-02-26 01:58:23">]>

 

If we modify this method with a closure though, we can extract a rabbitt by name maybe...

def get_rabbits
  @rabbitts = Rabbitt.all rescue nil
  lambda do |name|
    @rabbitts.each{|r| return r if r.name.downcase == name.downcase}
    puts name #never fires if return completes above
  end
end

 

And let's try that call again, see if we can find Teddy

get_rabbits.call('teddy')
  Rabbitt Load (0.3ms)  SELECT "rabbitts".* FROM "rabbitts"
 => #<Rabbitt id: 2, name: "Teddy", color: "blue", language: "English", speed: 674, created_at: "2016-02-26 01:58:23", updated_at: "2016-02-26 01:58:23"> 
2.3.0 :024 > get_rabbits.call('teddy').speed
  Rabbitt Load (0.4ms)  SELECT "rabbitts".* FROM "rabbitts"
 => 674

Very cool, so we can fetch the collection, and get a single rabbitt record out of the same method. And notice what we've returned is a Rabbitt object:

get_rabbits.call('teddy').class
  Rabbitt Load (0.2ms)  SELECT "rabbitts".* FROM "rabbitts"
 => Rabbitt(id: integer, name: string, color: string, language: string, speed: integer, created_at: datetime, updated_at: datetime) 

 

 

 

 

 

Things have gotten out of hand
Things have gotten out of hand

My desk today - this doesn't even take into account the 150 tabs I had open in multiple instances of 2-3 browsers on each machine.

What happened...

Well, it grew organically since yesterday, or maybe it was the day before. Hard to remember. At any rate, my goal was to install RabbitMQ. At least, that was the basic goal. First, just get it installed and running.

My secondary goal was to get it actually sending and receiving messages locally. By this I mean RabbitMQ installed on a computer, and a Rails app running on the same computer, communicating with each other.

The third and goal was to get it talking between 2 Rails apps on 2 different computers. So, I'll start with my primary goal. This I accomplished late yesterday actually, and really wasn't very difficult.

Phase 1

First, if you've never worked with RabbitMQ before, I highly recommend you read the docs. They have pretty solid documentation on the whole install process, along with several great tutorials to explain the language, behaviors, and concepts to beginners like myself.

I'm on a mac (obviously from above I suppose), and since I have set up my environment with Homebrew, I opt to install most new tech the same way, when and where possible. So I chose to install using Homebrew, though there is a mac tarball you can download and unpack if that's more to your liking.

The docs cover it well, but it's basically 2 commands:

brew update
brew install rabbitmq

 

Once the install has run, you should read the output from Homebrew. It's nice if you do, possibly a head-scratcher if you don't. They tell you neat things, like where to access the management interface, how to launch the server at startup, how to launch the server now, etc.

==> Caveats
Management Plugin enabled by default at http://localhost:15672 

Bash completion has been installed to:
 /usr/local/etc/bash_completion.d 

To have launchd start rabbitmq at login:
 ln -sfv /usr/local/opt/rabbitmq/*.plist ~/Library/LaunchAgents
Then to load rabbitmq now:
 launchctl load ~/Library/LaunchAgents/homebrew.mxcl.rabbitmq.plist
Or, if you don't want/need launchctl, you can just run:
 rabbitmq-server

 

Additionally, you should edit your .bash_profile or .profile file (read my other post on this), as that will enable you to run the server commands correctly from terminal.

Once that's done, start your RabbitMQ server up in terminal with the rabbitmq-server command. Then fire up http://localhost:15672. You should be able to access the management interface - the default user and password is guest/guest.

Screen Shot 2016-02-23 at 10.17.17 AM

You should see something similar to this, though there will most likely be no activity yet. All queues, connections should be zero.

So at this point you have the management interface up, and I tend to go in baby steps, to make sure all's well as it appears.

So first, head back to terminal, and tail the logs to see if there's any action on them.

 

tail -f /usr/local/var/log/rabbitmq/rabbit\@localhost.log

 

Next, in another terminal tab (hopefully you've got a couple open by now - one for logs, one for server, one or more for your application instances, perhaps one for miscellaneous - file tree stuff... maybe a dog running in another...) where your RabbitMQ server is running, try shutting it down. Verify you see something in the logs, and head back to the management interface and refresh it - it should come back with a blank page - not available.

So, with all that working, I decided I was good to move on to the next phase, which is implementing some code to interact with RabbitMQ.

 

Phase 2

Remember from above, my primary goal was to get RabbitMQ running. That goal complete, it was time to move on to the Rails part of the project. If you're into Python, Java, or some other flavor, this post probably won't be as interesting for you, though you may still get something out of it.

For this, I cd to a directory where I want my app to be stored - I have quite a few "site" folders (all projects wanting attention) - and I run some basic commands to get a Rails app up and running. One thing to note - make sure to include  gem 'bunny', '2.2.2'  in your Gemfile.

 

gem install rails --no-ri --no-rdoc
rails new rabbit_tester . && cd rabbit_tester
rvm use ruby-2.3.0
rvm gemset create rabbit
echo 'ruby-2.3.0' >> '.ruby-version'
echo 'rabbit' >> '.ruby-gemset'
rvm use ruby-2.3.0@rabbit
gem install bundler
bundle

So, that spits out a bunch of shit in between commands, while I grab some coffee and then continue. The docs say to set up 2 ruby files in isolation, which works fine for a basic litmus test (I did this too in fact), but I had wanted something where I could run either a rake command, or call a class method, or even better, load up a restful api in the browser which triggers the call to the RabbitMQ. I chose the last method, and grabbed the code from their tutorials to incorporate into my app.

My overall plan is to create a model with 2 methods, mapped to the send and receive functions. Then I'll create a couple of routes, map them to controller methods, and have these controller methods call the respective model's methods. This way I can fire up the page in the browser and watch the call go out in the logs, see it in the management interface, and see any output in my app in the browser as well.  My first step is to generate a model, run the required database migration.

rails g model Rabbitt name:string color: string language:string speed:integer
rake db:migrate

 

Now I am going to create 2 class methods, one for the sending of messages and one for receiving. Once created, I create an instance of my class (just for laughs), pull in some of the code from the RabbitMQ docs and tweak it a bit.

rails c
Rabbit.create(name: 'Brier Sr.', color: 'purple', language: 'High Rabbit', speed: 175)

 

class Rabbitt < ActiveRecord::Base

  class << self
    def send_amqp
      puts "beginning send method..."
      conn = Bunny.new
      conn.start

      ch = conn.create_channel
      q = ch.queue("rabbitt events")
      ch.default_exchange.publish("hello from #{Rabbitt.first.name} ....", routing_key: q.name)
      puts "Sent a notice from #{Rabbitt.first.name} ----------------"

      conn.close
    end

    def receive_amqp
      conn = Bunny.new
      conn.start

      ch = conn.create_channel
      q = ch.queue("rabbitt events")
      q.subscribe(block: true) do |info, props, body|
        puts "message received! #{body} ----------------"
        puts "props: #{props.inspect} ================"
        puts "info: #{info.inspect} ================"

        info.consumer.cancel

      end
    end

  end # end class methods ........
end

Cool, so that's done. Next is to generate a controller and the necessary view templates.

rails g controller rabbitts index send

For the send method, I modify the routes a bit:

resources :rabbitts do
  collection do
    get 'send/message', to: 'rabbitts#send'
  end
end

Right, at this point, I'm ready to fire up my server again and see if any of this generates anything. First I load up my rails app from terminal, and then in another terminal tab, I start my RabbitMQ server. Finally, I open a third terminal tab to tail the RabbitMQ logs.

rails s -p1234
rabbitmq-server
tail -f /usr/local/var/log/rabbitmq/rabbit\@localhost.log

In my first tab, I browse to localhost:1234/rabbitts/send/message , and success! In the Rails logs I see

beginning send method...
Rabbitt Load (0.2ms)  SELECT  "rabbitts".* FROM "rabbitts"  ORDER BY "rabbitts"."id" ASC LIMIT 1
CACHE (0.0ms)  SELECT  "rabbitts".* FROM "rabbitts"  ORDER BY "rabbitts"."id" ASC LIMIT 1
Sent a notice from Brier Sr. ----------------

In a second tab, when I browse  to localhost:1234/rabbitts, I see the refresh icon in the tab is incomplete, as if it's continually loading. This is because it's waiting for a response from RabbitMQ, and the connection has been left open. While there's nothing in the UI of the page (I didn't actually modify the view yet), in the Rails logs, I see what I was hoping for:

Started GET "/rabbitts" for 192.168.1.11 at 2016-02-22 20:15:33 -0800
Processing by RabbittsController#index as HTML
message received! hello from Brier Sr. .... ----------------
props: {:content_type=>"application/octet-stream", :delivery_mode=>2, :priority=>0} ================
info: {:consumer_tag=>"bunny-1456200933000-722471154864", :delivery_tag=>#<Bunny::VersionedDeliveryTag:0x007fd414073858 @tag=1, @version=0>, :redelivered=>false, :exchange=>"", :routing_key=>"rabbitt events", :consumer=>#<Bunny::Consumer:70274422964960 @channel_id=1 @queue=rabbitt events> @consumer_tag=bunny-1456200933000-722471154864 @exclusive= @no_ack=true>, :channel=>#<Bunny::Channel:70274422981440 @id=1 @connection=#<Bunny::Session:0x7fd4140b04d8 guest@127.0.0.1:5672, vhost=/, addresses=[127.0.0.1:5672]>>} ================
  Rabbitt Load (0.2ms)  SELECT "rabbitts".* FROM "rabbitts"
  Rendered rabbitts/index.html.erb within layouts/application (2.6ms)
Completed 200 OK in 398ms (Views: 381.5ms | ActiveRecord: 0.2ms)

My final two checks are to the RabbitMQ logs and the management interface. The logs show connection accepted,  accepting AMQP connection <0.8837.4> (127.0.0.1:62341 -> 127.0.0.1:5672) and the management interface is interesting. I notice that in the global counts, I see 1 queue, and 1 consumer, and 1 connection, yet no messages.

I rerun the test, this time watching the management interface, and sure enough, the message comes in, and gets queued (in the 'queued messages' chart at the top), and as soon as I refresh the /rabbitts view, the message is consumed and removed from the queue.

So far, it looks as though everything is functioning as I had hoped.

Phase 3

So the last piece is replicating this same behavior, but across multiple machines - a remote connection. This was my final goal, and came with a few hiccups.

My process was to keep my Rails app running on the RabbitMQ machine, given that it was already working. What I needed to do was disable either the receiving or sending code, and migrate that to another computer, in a separate app. As it turns out, you can have multiple consumers of the same queue on RabbitMQ, so in hindsight, disabling one or the other wasn’t really necessary.

That being said, I took a laptop, ran through the same process again - set up a sample Rails app using the Bunny gem, plugged in the code from the existing one which was working, and… spectacular fail. Nothing. Only shell errors “Cannot connect”, “connection refused”. The Rails logs looked like this:

E, [2016-02-22T19:56:02.250071 #33526] ERROR -- #<Bunny::Session:0x7fda69e84860 varker@192.168.10.11:15672, vhost=/, addresses=[192.168.10.11:15672]>: Got an exception when receiving data: IO timeout when reading 7 bytes (Timeout::Error)
W, [2016-02-22T19:56:02.251043 #33526] WARN -- #<Bunny::Session:0x7fda69e84860 varker@192.168.10.11:15672, vhost=/, addresses=[192.168.10.11:15672]>: TCP connection failed, reconnecting in 5.0 seconds

I checked my firewall settings on the computer running RabbitMQ - all looked good. Just in case, I turned it off completely, hoping that would solve the issue. It didn’t.

So let’s step through the process a bit and I can explain how it’s different from Phase 2.

First, there are now 2 clients in the game, so instead of ‘localhost’, ‘0.0.0.0’, or ’127.0.0.1’, we have to use the proper IP address for each.

So I ran ifconfig on each machine, giving me a 192.168.10.11 and 192.168.10.5 for the RabbitMQ and remote machines respectively.

So the first change that needs to be made is in the management interface of RabbitMQ, or in the config file. We’ve been leveraging the default user, ‘guest’. Guest is not allowed to connect across machines in RabbitMQ however, unless the config file is modified.

So there are two options here - modify the config file, or create a new user. There’s some pseudo code in the docs about the config settings, so first I followed this path, modifying /etc/rabbitmq/rabbitmq.conf. Then, just to be on the safe side, I went into the management interface in the browser and created a new user, ‘varker’, with admin priveleges.

The next change is in our Ruby model. We can no longer call Bunny.new without arguments. This was basically running off 'localhost', the default port '5672', and the default user/password combo of 'guest'/'guest' - all implicit. Now we have to do Bunny.new(:host => '192.168.10.11', port: 5672, user: 'varker', password: ‘xxxxx’ )

The other change needed for our rails apps is in the server instantiation. We actually need to bind to the correct IP and port. This means on the RabbitMQ machine I need to run

rails s -b 192.168.10.11 -p1234

And on the remote machine, I use it’s IP in the same fashion:

rails s -b 192.168.10.5 -p3000 (port is your choice..)

Then, the final change I missed the first time around, and what caused me endless anguish with the IO timeouts, is to modify the RabbitMQ env config file. Right, there’s a second config - /etc/rabbitmq/rabbitmq-env.conf. Its pretty basic out of the box - just a couple of variables: NODE_NAME, and NODE_IP_ADDRESS. This last one is most likely set to ’127.0.0.1’ by default, or ‘localhost’. To use it remotely, you need to modify this to point to the machine running the instance of RabbitMQ. In my case, ‘192.168.10.11’.

Then, the absolute last change - if you were accessing your management interface on http://localhost:15672, you’ll need to change the url to point to that same machine, in my case http://192.168.10.11:15762.

That done, I go into my final test workflow:

  1. Restart my RabbitMQ server
  2. Open another tab to tail the RabbitMQ logs
  3. Start both Rails apps on each machine.
  4. Fire up the Rails apps in browsers, and watch the Rails logs and RabbitMQ logs for output.
  5. Check the management interface for activity. One interesting point here, (see image below), the bind address listed should now be the IP you set in the env conf file.

bind address updated

For my test, I used the machine running the RabbitMQ instance, (the 10.11), as the sender, while my remote machine was the receiver. So I hit refresh on 192.168.10.11:1234/rabbitts/send/message, and watched as magically, the logs in my Rails app on 10.5 showed:

Started GET "/" for 192.168.1.5 at 2016-02-23 19:48:43 -0800
Processing by HomeController#index as HTML
waiting for messages from the big mac where the bunny queue 'rabbitt events' was set up ....
Message received! ------- hello from Brier Sr. .... ---------
props: {:content_type=>"application/octet-stream", :delivery_mode=>2, :priority=>0} ===================
info: {:consumer_tag=>"bunny-1456285723000-548533168304", :delivery_tag=>#<Bunny::VersionedDeliveryTag:0x007fdc745f5930 @tag=1, @version=0>, :redelivered=>false, :exchange=>"", :routing_key=>"rabbitt events", :consumer=>#<Bunny::Consumer:70292411003800 @channel_id=1 @queue=rabbitt events> @consumer_tag=bunny-1456285723000-548533168304 @exclusive= @no_ack=true>, :channel=>#<Bunny::Channel:70292424556060 @id=1 @connection=#<Bunny::Session:0x7fdc75fbd958 varker@192.168.10.11:5672, vhost=/, addresses=[192.168.10.11:5672]>>} ===================

Success! Now that I know how to set this up, it’s really fairly straightforward. The RabbitMQ docs are a great help and really well-done. Hope this helps someone. Ping me if you have questions or find errors/bugs - happy to help if I can, and I always welcome feedback.

 

 

 

I was playing around with RabbitMQ today. For those who don't know what it is, RabbitMQ is a message broker - or what some might call a bus, message queue, or message-oriented middleware. In the most simplistic terms, it's a middleman. It sits between 2 or more applications, receiving and sending messages back and forth, which in turn most likely trigger some action within one or more of the applications.

One of the nicest things about this is you logically decouple the application instances from each other, so they don't have to know about each other's structure, objects, or even language. A Python script can send a message to RabbitMQ, and on the other end of the queue, a Ruby app can consume it. Another nice point is scalability - if you find performance of the queues is suffering, you can throw more hardware (or virtualized hardware) at the RabbitMQ instance, without needing to touch either of your applications.

So intros aside, on to my troubles. One issue I was having is attempting to start the server. I had installed RabbitMQ with Homebrew, and so there are a couple of methods to interact with the server. You can run these two commands, launchctl load ~/Library/LaunchAgents/homebrew.mxcl.rabbitmq.plist
to start it, and launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.rabbitmq.plist
to stop it.

Drawbacks should be obvious. The other command available is rabbitmq-server. Whenever I attempted to run this command, I kept getting an error message: rabbitmq-server command not found

Upon re-reading the docs, I found the cause of the problem. They literally tell you, "The RabbitMQ server scripts are installed into /usr/local/sbin. This is not automatically added to your path..."

So, to fix it, simply open up your .profile or .bash_profile, and add the recommended line. In my case, I use vi, so:

$ vi ~/.bash_profile

On lines 5 and 6 I had:

PATH=$PATH:$HOME/.rvm/bin
PATH="/usr/local/bin":$PATH

On line 7, I added:

PATH=$PATH:/usr/local/sbin

Then I wrote, quit, and did a

$source ~/.bash_profile 

in my open Terminal tabs, and I was off and running with "rabbitmq-server"

I had a previous post on creating a CSS only multi-level flyout menu. I'm in the process of recovering that one, and will relink it when it's back up, but for now, a recent task (a.k.a take home test for an interview) asked me to create that very same menu, using a combo of JavaScript and CSS.

The idea of course, is to make it programmatic so it will scale to an infinite level of submenus. I find many of the tests we're asked to do during interviews involve some form of recursion - flatten a nested array of nested arrays, build minesweeper, and this one is no exception. So this was my solution for it. It's one way to do it - not the only way however.

I am including the original code in the snippets, though the running model below (is a bit wonky because of integration with WordPress I suspect), is a bit modified due to JavaScript scope conflicts and I added a div wrapper in the html to give sufficient height for the menu to display.

On to the design. My idea was to have an html element with a unique id to hang this menu off of.

HTML

So the html was pretty simple:

<ul id="dropdown_menu">
    </ul>

Like I said, simple. Now for the CSS.

CSS

The CSS needs to handle a few things - the styling of the unordered list and it's list items, plus any nested lists and list items. It also needs to deal with some state & interactivity - namely the concept of something being hidden vs. visible, and the mouseover, or hover, interaction animation.

Again, not overwhelmingly difficult - notice the craziness with the multiple nested uls though. That should probably be addressed for enhanced scalability.

html, body {
        padding: 0;
        margin: 0;
        font: normal 16px/135% sans-serif;
      }
      ul,
      ul li {
        list-style: none outside none;
        padding: 0;
        margin: 0;
      }

      .hidden {
        display: none;
      }

      ul li > ul {
        position: relative;
        top: -65px;
        right: -100%;
      }

      .menu-item {
        width: 200px;
        height: 70px;
        vertical-align: middle;
        line-height: 400%;
        text-align: center;
        background-color: lightblue;
        box-sizing: border-box;
        border: 1px solid black;
        opacity: 0.85;
      }
      .menu-item:hover {
        cursor: pointer;
        opacity: 1;
      }
      .menu-item > ul > .menu-item {
        background-color: violet;
      }
      .menu-item > ul > .menu-item > ul > .menu-item {
        background-color: lightgreen;
      }

      /* testing further levels with modified js object */
      .menu-item > ul > .menu-item > ul > .menu-item > ul > .menu-item {
        background-color: orange;
      }

Again, slight changes have been made to the working model below.

JavaScript

Finally the JS. This is where the bulk of the work is being done. I opted to use jQuery, just for convenience, though the entire thing can be done in native JS of course.

We're starting with a native JSON object. Originally, this was composed as 3 separate files - the js, css, and HTML file referencing the previous 2. Thus, the 'window' on the MENU variable so it was globally available.

window.MENU = [
      {
        'title': 'Item 1',
        'submenu': null,
      },
      {
        'title': 'Item 2',
        'submenu': [
          {
            'title': 'Sub 2 Sub1',
            'submenu': [
              {
                'title': 'Sub2 SubSub 1',
                'submenu': [
                  {
                    'title': 'Sub2 SubSubSub 1',
                    'submenu': null,
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        'title': 'Item 3',
        'submenu': [
          {
....

 

The most difficult thing about a task like this is probably structuring the design. I decided I wanted to keep it fairly simple. I'd start with variables for the HTML I wanted to insert into the parent, so an empty string will do for that, and something to hold the MENU object.

A couple of things about me - I like comments, and I try to be defensive in my coding, meaning it won't blow up if the unexpected happens. So this first declaration is just to return nothing basically, if for some reason the MENU object can't be parsed:

// defense ...
      if(MENU == null || MENU == undefined) {
        return false;
      }

Then the html variable is basically a document.getElementById('blah') ala jQuery.

//parent node to which will append further html
var html = $('#dropdown_menu');
var list = '';

 

Then I wanted a function which would slurp up the object and parse it, and a second function which would handle the action of creating lists or list items as needed. This first function is recursive, calling itself at each level as it descends:

function parseMenuBlock(data) {
        if(data.submenu == null) {
          list += createListItem(data.title, 1);
        }
        else {
          list += createListItem(data.title, 0);
          list += ('<ul class="hidden">');
          for(n in data.submenu) {
            parseMenuBlock(data.submenu[n]);
          }
          list += ('</ul>');
          list += closeListItem();
        }
      }

So this keeps appending onto the 'list' variable, the composed HTML string, as it's parsing the MENU object. It's looking at the submenu attribute and if its null, meaning it has no children, it just generates a list item for that block and stops. Otherwise, it creates the list item, and begins a new unordered list. Inside the unordered list, it recurses, calling itself to parse the next child level of the MENU object.

Obviously there's another method being called inside of here - the createListItem(). That I'm just passing the title attribute value to, so we can use that in the HTML title attribute, and a boolean flag. This flag decides whether we close the HTML for the list item ('</il>'), or leave it open (in the event there's a nested unordered list inside it).

// tackles the creation of a single list item element, close argument decides whether or not to close it or leave open for nested ul
function createListItem(data, close) {
  if(close == 1){
    return '<li class="menu-item" title="' + data + '">' + data + '</li>';
  }
  else {
    return '<li class="menu-item" title="' + data + '">' + data;
  }
}

function closeListItem() {
  return  '</li>';
}

 

Lastly, we need to kick the whole thing off by opening a loop to iterate over the MENU object, calling our ingestion method - parseMenuBlock(), and return the list value, and append it to the DOM object

for(i in MENU) {
        parseMenuBlock(MENU[i]);
      }
html.append(list);

 

The other anonymous functions in here deal with interactions, so just to take a quick look at those. This first one is called when the user's mouse moves into a menu item. If it can find a hidden child item, it reveals it, otherwise, do nothing.

$(document).on('mouseenter', 'li', function(e){
        //check if the element is hidden and remove 
        if($(this).children(':first').hasClass('hidden')) {
          $(this).children(':first').toggleClass('hidden');
        }
        //otherwise leave it alone...can be removed... left for readability
        else {
          return;
        }
      });

 

This next one sets a timeout to hide the child after the user moves the mouse away - a slight delay of 250ms in case the user is inaccurate with the mouse. Notice the t= $(this). That sets t to the object we're binding the mouse event to - in this case, an 'li'.

//bind mouseleave function to a delayed visibility toggle
      $(document).on('mouseleave', 'li', function(e) {
        var t = $(this);
        setTimeout(function(){
          t.children(':first').toggleClass('hidden');}, 250);// end setTimeout ...
      });

 

This last one is probably not desirable actually, but I was using for debugging and testing. It simply alerts the title attribute for the bound element. Notice the $(document).on(event, element, function()) syntax. This is necessary because at the time the page is loaded, none of these elements are present in the DOM, so the DOM has no knowledge of their existence. So we need to bind at the document level, to dynamic elements being added after the initial render of the DOM.

//bind click event to dynamically inserted elements
      $(document).on('click', 'li', function(e) {
        e.stopPropagation();
        alert($(this).attr('title'));
      });

 

And that's pretty much it. As I mentioned, below is a slightly wonky version of the menu in action. Enjoy, and feel free to comment.

Today's mission was randomizing dice rolls, for a given number of players at a table. The concept obviously comes in handy in a number of board games, or at a gambling table, and several simple dice-based games as well.

For the purposes of this demo, I decided on using a six-sided die, and we'll have any number of players, say 2-10. When designing this, I need methods to handle the actual action of rolling the dice, and then another method to handle the randomization, and any algorithm-related activity of the dice roll.

Let's start with the first one, we'll call it rollDice(). To keep it simple, I'm going to just pass it a number of dice to roll. We'll store the results in an array, and return the array of values.

var rollDice = function(numDice) {
    var roll=[];
    //do something numDice times ...
    console.log('roll', roll);
    return roll;
  };

Great, we're off to a rolling start. That's returning an empty array, which is what we want. Once we push values in there, it will be populated.

Next up is our second function, the randomizer, and I'm going to call that randomizeDiceRoll(). So for that one, to keep it simple, I'll define the dice configuration within the method, but this would be a perfect situation for an external config setting of some kind - a global object, a call() implementation, or a Die class which holds config for multiple types and shapes of dies. This one will simply randomize the outcome based on the number of sides in the die.

var randomizeDiceRoll = function() {
    var diceSides = [1,2,3,4,5,6];
      return Math.floor((Math.random() * diceSides[diceSides.length-1]) + 1);
 };

This we can test a few times in console and see it execute, and it appears to be handling the outcome fairly randomly, so we're good here. Let's move on to the last step, which is plugging this into our previous method.

var rollDice = function(numDice) {
    var roll=[];
    for(var i=0;i<numDice;i++) {
      roll.push( randomizeDiceRoll() );
    }

    console.log('roll', roll);
    return roll;
  };

Testing that in console, I can see I'm getting 3 rolls back for 3 players, 2 for 2 players, etc. So this is working as well.

rollDice(3)
•>  roll [3, 5, 2]
[3, 5, 2]
rollDice(2)
•>  roll [1, 2]
[1, 2]
rollDice(8)
•>  roll [1,2,2,5,4,6,1,1]
[1, 2, 2, 5, 4, 6, 1, 1]

So we hit a snag. What happens when we have a tie? Well, we can just force everyone to re-roll, adding a new boolean variable - tie, along with some recursion to our rollDice() method. Something like this:

var tie = false;
 
roll.forEach(function(n, idx) {
  if(roll[idx] == roll[idx+1]) {
    tie = true;
  }
});
if(tie == true) {
  rollDice(numDice);
}

So this works - I rolled for 3, got a tie, and it re-rolled, eliminating the tie:

rollDice(3);
roll [3, 3, 5]
roll [2, 3, 1]

Tie problem solved but now we have an additional problem. If you look at those results, the last item in the first array originally had the highest score, placing them in first position to start a game, or possibly win a battle. After re-rolling though, they are actually in last, unless we're using the numbers in reverse order, either way, their fortune has been flipped on its head. So let's fix that

var rollDice = function(numDice) {
    var roll=[],
        diceSides = [1,2,3,4,5,6];
    for(var i=0;i<numDice;i++) {
      roll.push( randomizeDiceRoll(diceSides) );
    }

    console.log('roll', roll);
  
    checkForTies(roll, diceSides);
};
  var randomizeDiceRoll = function(diceSides) {
    //var diceSides = [1,2,3,4,5,6];
    return Math.floor((Math.random() * diceSides[diceSides.length-1]) + 1);
  };



var checkForTies = function(roll, diceSides) {
  if(roll.length > diceSides.length) {
    return roll;
  }
  else {
    roll.forEach(
    function(n, idx) {
      if(roll.indexOf(n) != roll.lastIndexOf(n)) {
        tie = true;
        roll[roll.indexOf(n)] = randomizeDiceRoll(diceSides);
        roll[roll.lastIndexOf(n)] = randomizeDiceRoll(diceSides);
        checkForTies(roll, diceSides);
      }
  });
  return roll;
  }
  
}

rollDice(6); //should end with unique values for each array element
rollDice(7); //there will be duplicate elements

OK, so you can see we've restructured things a bit. We're now passing the diceSides to each of the child functions (not ideal, but it works for now), and we check for a tie. If the number of sides of the dice is greater than or equal to the number of players rolling, we can sort out the tie - if not, we just return the original array of values, as it's mathematically impossible for there NOT to be a tie (ex: 7 players with a 6-sided die).

For now, we have a solution for our randomized dice roll. Some enhancements would be a config flag to say whether or not to trigger the tie-resolving method (you may want it in certain cases, but not in others), and a cleaner implementation architecturally. So I'll work on those soon.

Thanks for reading - feedback welcome.

Another day and yet another tech challenge. I was recently confronted with this and although I couldn't tackle it during an interview session, once I finished the interview (lost the job of course), and was able to give it some thought, I realized this problem really isn't that difficult.

Context for the problem is this - I give you a string, and you need to find the longest palindrome in the string, or the longest word spelled the same forward as backward. So for example, if you were given "aghbrettegh", I'd expect to get 'ette' back.  As usual, there are multiple ways to approach solving this, so this is just one possible route. If you have a cleaner, better, or different one let me know.

There are two main challenges here - the first is to identify what a palindrome is. I tackled that part first, and wrote a boolean method which, as you might have guessed, returns true if the string is a palindrome, and false if it isn't. Looks like this in Ruby:

def is_palindrome? string
  string.split('').each_with_index do |s, idx|
    return false if s != string.slice(string.length-1 - idx, 1)
  end
  true
end

So basically we're just slicing the string 1 character at a time, from either end of the string, and comparing them. This worked pretty well, so we'll continue with the second part shortly.