Category: development

Eclipselink static weaving

I’m playing with a new project and decided to get eclipselink static weaving working in this one. I started on the official eclipselink project documentation on the subject. That’s nice and all, but it doesn’t say anything about getting the weaving to work with maven or eclipse. I really wanted both. Here’s what I did.

First, in persistence.xml you should add the following property:

    <properties>
      <property name="eclipselink.weaving" value="static" />
    </properties>

My maven project has several modules. domain-api contains the entity definitions. domain-impl contains the code for interacting with the database. That means that my persistence.xml is contained in domain-impl and the @Entity classes are in domain-api. That’s alright. To get this all working I decided to use the command line option rather than use the ant task.

The weaving needs to take place on the entities, so the weaving step is placed in the domain-api pom.xml. Within build/plugins I added this plugin.

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.2.1</version>
        <executions>
          <execution>
            <id>weave-classes</id>
            <phase>process-classes</phase>
            <goals>
              <goal>java</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <mainClass>org.eclipse.persistence.tools.weaving.jpa.StaticWeave</mainClass>
          <commandlineArgs>-classpath %classpath -loglevel FINE -persistenceinfo ${basedir}/../domain-impl/src/main/resources ${basedir}/target/classes ${basedir}/target/classes</commandlineArgs>
        </configuration>
      </plugin>

That’ll run the java program to weave the class files in place. Note that my -persistenceinfo argument points to ../domain-impl/src/main/resources. That’s because the StaticWeave class will look for META-INF/persistence.xml within that directory, and my persistence.xml is contained in the domain-impl module, not within domain-api. If you are using maven resource filtering on your persistence.xml this will cause a problem since domain-impl builds after domain-api. That’s not a problem in my case so I’m going to be lazy and not address it.

Once you have that in your pom you should be able to do a mvn clean install and see output something like:

[INFO] --- exec-maven-plugin:1.2.1:java (weave-classes) @ domain-api ---
[EL Config]: metadata: 2012-11-23 23:15:42.798--ServerSession(1166215941)--Thread(Thread[org.eclipse.persistence.tools.weaving.jpa.StaticWeave.main(),5,
org.eclipse.persistence.tools.weaving.jpa.StaticWeave])--
The access type for the persistent class [class com.xyg.model.JoelTest] is set to [FIELD].

I added line breaks for formatting. Anyway, that kind of output means things are working.

Sadly, Eclipse’s maven integration isn’t smart enough to figure this part of the pom out. If we tell Eclipse to ignore this part of the build then the classes won’t get weaved and it’s likely that if you try to run the project from within eclipse it’s not going to work properly. Fortunately, we can work around this.

Within the same pom (in my case, in domain-api) you can add another plugin. This plugin is NOT within the plugins element, but is within a pluginManagement element. You can get eclipse to generate the entry for you by telling it to ignore the execution when it tells you it has an error because it has no lifecycle mapping for the given execution. When you do that it’ll generate an xml block in your pom.xml that will look like this:

    <pluginManagement>
      <plugins>
        <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
        <plugin>
          <groupId>org.eclipse.m2e</groupId>
          <artifactId>lifecycle-mapping</artifactId>
          <version>1.0.0</version>
          <configuration>
            <lifecycleMappingMetadata>
              <pluginExecutions>
                <pluginExecution>
                  <pluginExecutionFilter>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <versionRange>[1.2.1,)</versionRange>
                    <goals>
                      <goal>java</goal>
                    </goals>
                  </pluginExecutionFilter>
                  <action>
                    <execute/>
                  </action>
                </pluginExecution>
              </pluginExecutions>
            </lifecycleMappingMetadata>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>

The version eclipse generates will say something like <ignore></ignore> in the action section of this configuration. If you simply change that to <execute/> then eclipse will execute it. It will execute it every time, even on incremental builds, so hopefully it isn’t too intrusive. I’m just getting started on this project so I don’t have many entity classes yet, but if there’s an issue I’ll get back and update this post.

With this configuration I’m able to execute my integration tests from the command line and I’m also able to run the tests and launch the webapp from within eclipse, and I don’t incur the runtime penalty of dynamic weaving.

Advertisements

Jackson Mixins

You are working with a third party library. You need to serialize an object from that library to JSON. Or, in my case, I needed to serialize an implementation of an interface defined in the third party library. In any case you can’t modify the class you need to serialize, but you also need to change the way the class is mapped. Jackson provides a great mechanism to work around this using what they call MixIns.

Let’s say you are given this:

public interface ThirdPartyInterface {
  long getItemID();
  float getValue();
}

For some reason beyond your control, you need to use id instead of itemID in the JSON as the key for getItemID. To make things even more awesome, you need to have quotes around the itemID and the value, but you don’t want quotes around EVERY numeric field, just those two. With Jackson, I create my mixin interface, and I provide the Jackson annotations that I would like to apply on the instances of the ThirdPartyInterface to my new one.

public interface MyMixin {
  @JsonProperty("id")
  @JsonSerialize(using=ToStringSerializer.class)
  long getItemID();

  @JsonProperty("value")
  @JsonSerialize(using=ToStringSerializer.class)
  float getValue();
}

Now you can see that I have the JsonProperty annotations in there to change the name of the key, and I have the JsonSerialize annotation in there, using the Jackson builtin ToStringSerializer to convert the long and float values into Strings, which will ensure they are quoted in the JSON output.

In order to use my Mixin, I configure the ObjectMapper to do so as follows.

  ObjectMapper mapper = new ObjectMapper();
  mapper.getSerializationConfig().addMixInAnnotations(ThirdPartyInterface.class, MyMixin.class);

In my case, I have several implementations of the ThirdPartyInterface and configuring the mixin as above applies to all implementations. Pretty slick.

Backing up your database to Amazon S3

So now that you have your application running on an AWS EC2 instance, you need to backup the data somehow.  In my case, it’s a postgres database and I wanted to back it up into Amazon S3 within my same AWS account.  I wanted to have a backup for every day of the week, which would roll.  What I mean is that I would have a backup for Monday, and every Monday it would overwrite the previous Monday’s backup.  That way I would have a rolling 7 day backup. but not have a bazillion copies of the database that I have to manually get rid of.  Anyway, on to the code.

I wrote a little bash script that I then put into a cron job.  First, there’s a touch of setup to be done.  Wherever you are going to be running the job, you will need to install and configure s3cmd.  It’s a great little utility for hitting s3 from the command line.  The very simple instructions for configuring s3cmd are on that first page and shouldn’t take you more than 5 minutes.  I’ve run it on OSX Lion and also on my AWS instance and had no issues.

Next, is the bash script.  Here it is.

#!/bin/bash

PGDUMP=pg_dump
EXPORTFILE=`date +%A`.sql
COMPRESSEDFILE=${EXPORTFILE}.tgz
BUCKET=<your bucket name>
S3CMD=~/bin/s3cmd-1.0.1/s3cmd

$PGDUMP -f ./$EXPORTFILE -cb -F p --inserts -U <your user> <your database>
tar -czf ${COMPRESSEDFILE} ${EXPORTFILE}

$S3CMD put ./${COMPRESSEDFILE} s3://${BUCKET}

You’ll need to set PGDUMP to point to your pg_dump script if it isn’t in your path. Also set S3CMD to point to wherever you installed s3cmd.  If you prefer other options for pg_dump, or if you are using some other database, you can modify the $PGDUMP line to do whatever you need.

On Monday the script will create a file named Monday.sql and a compressed archive named Monday.sql.tgz.  It’ll then upload Monday.sql.tgz to your s3 account.  You could easily add another line at the end of this script to remove the exported file and the archive using


rm $EXPORTFILE $COMPRESSEDFILE

Finally, you’ll need to schedule this to be run once per day.  This can be done by running crontab -e and then using the following line in the crontab file:


0 2 * * * ~/backupdb.sh

That will run the script every morning at 2.  You can change the hour for whatever fits your needs.

The final task for me is going to be creating a similar script that will run every week and keep the last 4 weeks of backup.  I’m planning to do that using %W on the date command to get the week of year and do some math using the week number in the file name to create the new file and remove the old ones.  I guess I’ll leave that as an exercise for the reader.

Amazon Web Services Alarm for HTTP Server

So you’ve written an app and you’re hosting it on an AWS EC2 instance.  For whatever reason you have only the one server up with no load balancer in front of it.  You want to set an alarm in AWS so that if the server goes down you’ll know right away, but how can you do it?

I wrote a simple bash script to ping a special URL in my web application.  The response from the URL is simply the text “healthcheck ok” with a 200 response code.  The script checks for that text.  If it exists in the response, then it sends a 1 up to AWS as a custom metric.  If it doesn’t, then it sends a 0.

#!/bin/bash
while :
do
  stat=0
  healthcheck=`curl --connect-timeout 5 --max-time 7 --fail --insecure --silent https://localhost/healthcheck`
  if [ "healthcheck ok" = "$healthcheck" ]
  then
    stat=1
  fi
  mon-put-data --metric-name HttpHealthCheck --namespace YourNamespace --dimensions "server=prod" --value $stat
  sleep 60
done

In order for the script to run, you’ll need to have done all the authentication setup for the AWS scripts and ensure you have a version of them that includes the mon-put-data script.  For testing, you can run the curl command on the command line.  You can do the same with mon-put-data.

In my experience, it took a few minutes for the custom metric to show up the first time I sent it.  Once it settles in you should be able to select it from the metrics in CloudWatch.  The final step is to setup the alarm.

You should be able to set an alarm to go off when the value of the metric is <= 0.  I tested it by shutting down my web server and I got the alarm notification within about a minute.

If your health check isn’t started (which you can do with $nohup ./healthcheck.sh &) then you won’t get samples and in my test no alarm was sounded.  So, I set another alarm.  For any metric, you can set an alarm based on the value, or based on the samples.  Just choose the “samples” statistic from the drop down.  Set the alarm to go off if samples <= 0.  Also add another action and set it to go off on INSUFFICIENT_DATA, meaning that there are not enough samples, which likely means your script wasn’t started, or has failed.

Once your app is super popular, you can look at the load balancer, which I believe allows for setting alarms based on HTTP response times etc. but I think this’ll do until I get there.

Removing A Dragged And Dropped List Item

In a previous post I mentioned how to take a table row and drag it onto a sortable list. The problem with that is that there was no way to remove the item once it was dropped on the list. So, I modified the original code so that the dropped item now has a button that allows for removal of the item. Here is the new version in its entirety:

        var qTable;
        var newSurvey;
        // create the fancy datatable
        $(function() {
            // setup the datatable
            qTable = $('#questionTable').dataTable( {
                    "aoColumns": [
                                  { "asSorting": [ "desc", "asc" ] },
                                  { "asSorting": [ "desc", "asc", "asc" ] },
                              ]
                    , "bJQueryUI": true
                }
            );
            
            $(qTable.fnGetNodes()).draggable({
                opacity: 0.7,
                helper: function() {
                    var text = this.children[0].innerText;
                    var result = "<li id='"+this.id+"'>"+text+"</li>";
                    return result;
                },
                connectToSortable: '#newSurvey'
            });

            newSurvey = $('#newSurvey');
            newSurvey.sortable({
                beforeStop: function( event, ui ) {
                    var id = ui.helper.attr( "id" );
                    if ( id.indexOf( 'li' ) == -1 ) {
                        id = 'li' + id;
                    }
                    var text = ui.helper.text();
                    var li = "<li id='"+id+"'><span class='ui-icon ui-icon-circle-close' onclick='remove(\""
                            +id+"\")'></span>"+text+"</li>";
                    $(ui.item).replaceWith( li );
                },
            }).disableSelection();
        });
        
        function remove(id)
        {
            var li = $('#'+id);
            li.fadeOut('fast', function() { li.remove();});
        }

So, the biggest difference between this and the previous is in the “beforeStop” function. The first being this block:

                    if ( id.indexOf( 'li' ) == -1 ) {
                        id = 'li' + id;
                    }

The problem I had was that when dropping from the table row, everything was awesome, but if I re-ordered within the list, then I kept pre-pending another ‘li’ to the front of the id. So I would end up with a row with an id of ‘lilili123’ or something like that. Undesirable at best. So now, I check to ensure it only has one li prefix.

The second difference, and the main one for this post, is the addition of the remove function and the button to remove it when dropped, contained here:

                    var li = "<li id='"+id+"'><span class='ui-icon ui-icon-circle-close' onclick='remove(\""
                            +id+"\")'></span>"+text+"</li>";
                    $(ui.item).replaceWith( li );

and here:

        function remove(id)
        {
            var li = $('#'+id);
            li.fadeOut('fast', function() { li.remove();});
        }

The first section is the new code to replace the helper from the table row draggable with the list item, including the button for removal. If that sentence didn’t make sense, then go back and read the post linked above to get the details. Since this is all based on jquery, I used a jquery icon for the button. It is nice because then it will mesh with whatever jquery theme you are using.

The remove function uses a jquery animation to quickly fade the list item out and then remove it from the list. You must call .remove() to get it out of the list altogether.

The last wrinkle I have in this is that a user can drag the same item from the table onto the list, resulting in multiple copies of the list item, but that’s a problem for another day.

Get the “Next” value in a Java Enum

Java Enums. An awesome addition to Java 1.5 so we could avoid using public static ints for that purpose. I’ve been using them for some time with success and never noticed one deficiency until now. You can get the ordinal of an enum value with the ordinal() method. That is basically the index in the order the values were declared. So, if your enum look something like this:

 public enum Planet { MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE }

In this case, MERCURY would have an ordinal of 0, then VENUS 1, and so forth. Now, what if you want to iterate through them? You can get all the values of an enumerated type as an array using the values() method. Cool, right? Well, what if I don’t want to iterate through them, but I want to simply progress from one to the next. It would be cool if math operators (like + and -) would let you go from one to the next, but that’s not the case. I had a need to go from one to the next, so I changed my enum by adding the following method.

 private enum Planet { MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE;
    public Planet getNext() {
      return this.ordinal() < Planet.values().length - 1
          ? Planet.values()[this.ordinal() + 1]
          : null;
    }
  }

Now, if I do Planet.MERCURY.getNext() I would get VENUS. This takes advantage of the ordinal of each entry (which you cannot assign in any other way than the order in which you declare the enum values) and the values method, indexing into the values array to get the next value. If you attempt to go off the end, it’ll return null. It would be simple to make it wrap instead if that makes sense for your case. It would also be trivial to take this and implement a “getPrevious” if you have a need to go in reverse.

Erlang Concurrency Demo Application

As I said in my last post I was responsible for a demo in Erlang today. Before starting this application, I had about 2 hours of experience programming in Erlang. Day 3 in Bruce Tate’s book, Seven Languages in Seven Weeks focused on the concurrency aspects of Erlang. I was looking for an example program I could write that would demonstrate this, and didn’t want to just copy the example from the book. I asked on StackOverflow.com and didn’t really get anything I wanted to tackle.

Finally, last night while on my way to Kenpo I was able to think up this cool application. One process would be the air traffic control tower. Then, other processes would be all of the airplanes. Here’s the whole program

-module(aircontrol).
-export([run/0, fastrun/0, tower/0, createPlane/5, removePlane/2, addPlane/3]).

% method to run the program, creating a tower and some planes.
% in this run, 4 of the 5 planes crash
run() ->
  Tower = tower(),
  createPlane(Tower, 1, 5, 5, 2000),
  createPlane(Tower, 2, 1, 1, 4000),
  createPlane(Tower, 3, 1, 5, 6000),
  createPlane(Tower, 4, 5, 3, 10000),
  createPlane(Tower, 5, 5, 1, 5000).

% all planes survive here
fastrun() ->
  Tower = tower(),
  createPlane(Tower, 1, 5, 5, 30),
  createPlane(Tower, 2, 1, 1, 10),
  createPlane(Tower, 3, 1, 5, 30),
  createPlane(Tower, 4, 5, 3, 10),
  createPlane(Tower, 5, 5, 1, 10).

 

%%%%%%%%%%%%% Tower methods %%%%%%%%%%%%
tower() -> 
  io:format( "Tower ready for duty~n" ),
  spawn( fun() -> tower(lists:duplicate(25, null ))end).

tower(Occupied) ->
  receive
    {arrive, {Plane, Id, 3, 3 }} ->
      io:format("Tower: Flight ~p, welcome home.~n", [Id] ),
      tower(removePlane(Plane, Occupied));

    {arrive, {Plane, Id, X, Y }} ->
      {NewX, NewY} = getBearing( X, Y),
      io:format( "Tower: Flight ~p, please head to bearing (~p, ~p)~n", [Id, NewX, NewY]),
      Plane ! {bearing, getBearing( X, Y )},
      tower( addPlane( Plane, ((Y-1)*5)+X, removePlane( Plane, Occupied )));

    _ -> io:format( "Tower: I don't understand. ~n" )
end.

removePlane(Plane, List) -> lists:map(
  fun(X) -> 
    if 
      X == Plane -> null; 
      true -> X
    end
  end
, List).

addPlane(Plane, Index, List) -> 
  Occupant = lists:nth( Index, List ),
  if
    Occupant /= null ->
      Occupant ! crash,
      Plane ! crash,
      removePlane(Occupant, List );
    true ->
      lists:append([lists:sublist(List, Index-1), [Plane], lists:sublist(List, Index+1, 25)])
  end.

% get the next bearing as an X,Y tuple
getBearing(X, Y) ->
  if
    Y /= 3 -> {X, getBearing(Y)};
    true -> {getBearing(X), Y}
  end.

% Get a component of the next bearing
getBearing(Num) ->
  case Num of
    1 -> 2;
    2 -> 3;
    3 -> 3;
    4 -> 3;
    5 -> 4
  end.


%%%%%%%% Plane methods %%%%%%%%

createPlane(Tower, Id, X, Y, Speed) ->
  Plane = spawn(fun() -> plane(Tower, Id, Speed) end ),
  Plane ! {new, {X, Y}}.

plane(Tower, Id, Speed) ->
  receive
    {new, {X, Y}} ->
      io:format("Flight ~p created at (~p, ~p)~n", [Id, X, Y]),
      Tower ! {arrive, {self(), Id, X, Y }},
      plane(Tower, Id, Speed);
  
    {bearing, {X, Y}} ->
      io:format("Roger that tower, Flight ~p heading to bearing (~p, ~p)~n", [Id, X, Y]),
      timer:sleep(Speed),
      Tower ! {arrive, {self(), Id, X, Y}},
      plane(Tower, Id, Speed);

    crash ->
      io:format("MAYDAY! MAYDAY!, Flight ~p is going down!~n", [Id])
end.

Alright, what is going on here. You have a playing field that is a 5×5 grid. Each plane will be in one section of the grid at a time, so a plane that is at location (1,1) is in the top left corner, and a plane at (5,5) is in the bottom right corner. The airport (and the control tower) is at (3,3) and if a plane gets to the airport then it lands and is not tracked anymore.

Each plane has a flight number, coordinates, and a speed. The speed may be counter intuitive because the lower the number, the faster the plane flies. A plane with a speed of 2000 means that it takes 2000 milliseconds (or 2 seconds) to go from one square to the next. If two planes are in the same square in the playing field, then they collide and crash. Obviously we don’t want this to happen, but whoever is running the tower isn’t very good at their job.

When a plane arrives at a new square it checks in with the tower. The tower then tells it which square to go to next. The plane travels at its speed to the next square, checking in with the tower when it arrives, and getting new coordinates from the tower, and so on, until the plane arrives at the airport.

So, let’s step through and see where in the code this is all happening.

run() ->
  Tower = tower(),
  createPlane(Tower, 1, 5, 5, 2000),
  % create more planes here.

The run method takes care of creating the tower, and the planes, which sets everything in motion. When we call tower(), here’s what happens


tower() -> 
  % print a method to the user telling them that the tower is starting up.
  io:format( "Tower ready for duty~n" ),

  % spawn the tower process.  This is a little different than the spawn code in the book.  In the book none of the functions
  % used to spawn a process took any parameters.  Here we need to pass a list that says which places on the grid are 
  % currently occupied by planes.  I seed that list with 25 null values.  25 for the 5x5 grid, using an offset scheme within
  % the list to represent the different rows in the grid.
  spawn( fun() -> tower(lists:duplicate(25, null ))end).

After spawning the tower, it goes into its receive loop. The receive loop accepts one type of message which contains the atom
receive and a tuple containing the Plane process, the flight number, and the (X,Y) coordinates that the plane arrived at. There are two cases I handle here, the first being when the plane has arrived at the airport safely, and the second being where the tower needs to tell the plane where to go to next.

tower(Occupied) ->
  receive
    {arrive, {Plane, Id, 3, 3 }} ->
      % in this case, the plane has arrived at the airport
      io:format("Tower: Flight ~p, welcome home.~n", [Id] ),

      % since the plane has landed, remove it from the list of planes that are in the air.
      % and recursively call ourselves with the new list so we can receive messages from more planes.
      tower(removePlane(Plane, Occupied));

    {arrive, {Plane, Id, X, Y }} ->
      % in this case the plane has arrived at some square and needs directions on where to go next.

      % Here we get the new bearings for the flight
      {NewX, NewY} = getBearing( X, Y),
      io:format( "Tower: Flight ~p, please head to bearing (~p, ~p)~n", [Id, NewX, NewY]),

      % and here we send the bearings to the plane.
      Plane ! {bearing, getBearing( X, Y )},

      % next we change the location of the plane in the grid.
      tower( addPlane( Plane, ((Y-1)*5)+X, removePlane( Plane, Occupied )));

    _ -> io:format( "Tower: I don't understand. ~n" )
end.

I’m not going to go into the guts of how we figure out where the plane should go. The tower will always move a plane on the Y axis until it gets to 3, then it moves it along the X axis toward the airport. This isn’t the greatest algorithm in order to avoid a collision, but it is what it is.

The code where we figure out if we have a crash is in the addPlane method, which is as follows:

addPlane(Plane, Index, List) -> 
  % get the current occupant of the target space
  Occupant = lists:nth( Index, List ),

  if
    Occupant /= null ->
      % if the occupant isn't null, then we have a collision.
      % send a message to each of the planes in the space letting them know there's a problem.
      Occupant ! crash,
      Plane ! crash,

      % because Plane is not in the list, we only need to remove the Occupant.
      removePlane(Occupant, List );

    true ->
      % otherwise, Occupant is null, so we can just add this plane to the list.
      lists:append([lists:sublist(List, Index-1), [Plane], lists:sublist(List, Index+1, 25)])
  end.

Now, on to the code for the airplanes. First, the code to create a new plane. This is a convenience method since we could obviously spawn them and send the message ourselves


createPlane(Tower, Id, X, Y, Speed) ->
  % spawn the process, passing in the tower, flight id, and speed
  Plane = spawn(fun() -> plane(Tower, Id, Speed) end ),

  % then we send a message to the process, letting it know its starting location
  Plane ! {new, {X, Y}}.

Next, we need a receive loop for the plane so it can get the messages back from the tower. Receive accepts three messages, either the atom new with coordinates, the atom bearing with coordinates, or the atom crash. Perhaps the first two could be combined into a single match, but I implemented them separate. Here is the implementation.

plane(Tower, Id, Speed) ->
  receive
    {new, {X, Y}} ->
      io:format("Flight ~p created at (~p, ~p)~n", [Id, X, Y]),

      % we need to get on the radar with the tower, so tell them where we are so they can tell us where to go next
      Tower ! {arrive, {self(), Id, X, Y }},

      % now recurse into our receive loop again
      plane(Tower, Id, Speed);
  
    {bearing, {X, Y}} ->
      io:format("Roger that tower, Flight ~p heading to bearing (~p, ~p)~n", [Id, X, Y]),

      % the second receive pattern sleeps for Speed ms to simulate the time it takes to fly from
      % one square to the next
      timer:sleep(Speed),

      % once we arrive, we need to tell the tower where we are, then recurse into the loop again to accept more messages.
      Tower ! {arrive, {self(), Id, X, Y}},
      plane(Tower, Id, Speed);

    crash ->
      % if we crash, we don't recurse back into the receive loop because our process is done.
      io:format("MAYDAY! MAYDAY!, Flight ~p is going down!~n", [Id])
end.

So, there you go. A sample concurrency implementation written in erlang made up completely in my head. I was very happy with how this turned out, and it only took me a couple hours to program it. Yeah, the meat of the implementation (without the run methods) is only about 80 lines, but it does a lot in those lines, and I think it’s something coming from an entrenched OO programmer.