Monthly Archives: August 2013

You are browsing the site archives by month.

Deploying My Perl Application to dotCloud

dotCloud provides an easy way for you to show your Web application to the world.

This is how I deployed my Moving Company Travel Time Calculator on dotCloud.

Create the dotCloud application.

traveltime > dotcloud create traveltime
    ==> Creating a live application named "traveltime"
    ==> Application "traveltime" created.
        Connect the current directory to "traveltime"? [Y/n]: Y
    ==> Connecting with the application "traveltime"
    ==> Connected with default push options: --rsync

It looks like the application has been created. I then created a configuration file, “dotcloud.yml”.

www:
  type: perl
  approot: traveltime
  requirements:
    - App::cpanminus

Then connect..

traveltime > dotcloud connect traveltime
    ==> Connecting with the application "traveltime"
    ==> Connected with default push options: --rsync

I need to tell “app.psgi” who my Dancer2 script is.


traveltime > echo "require 'bin/app.pl';" > app.psgi
  

Then deploy the application


traveltime > dotcloud push
    ==> Pushing code with rsync from "./" to application traveltime
        building file list ... done
        ./
        dotcloud.yml
        .dotcloud/
        .dotcloud/config
        traveltime/
        traveltime/Changes
        traveltime/MANIFEST
        traveltime/MANIFEST.SKIP
        traveltime/Makefile.PL
        traveltime/README.pod
         ...
         14:34:17.360184: [www] Successfully installed Dancer2-0.04
         14:34:17.539632: [www] <== Installed dependencies for .. Finishing.
         14:34:17.540369: [www] 49 distributions installed
         14:34:22.529592: [www] Build completed successfully. Compiled image size is 11MB
         14:34:22.548716: [www] Build successful for service (www)
         14:34:22.563869: --> Application (traveltime) build is done
         14:34:22.582326: --> Provisioning services... (This may take a few minutes)
         14:34:22.599485: [www] Using default scaling for service www (1 instance(s)).
         14:34:22.651213: [www] Using limits for service "www": ram=64M
         14:34:22.696068: [www.0] Provisioning service (www) instance #0
         14:34:27.002331: --> All services' instances have been provisioned. Installing code...
         14:34:27.015045: [www.0] Installing build revision rsync-1371306712243 for service (www) instance                    #0
         14:34:34.852233: [www.0] Running postinstall script...
         14:34:35.582842: [www.0] Launching...
         14:34:36.905954: [www.0] Waiting for the instance to become responsive...
         14:34:37.910787: [www.0] Re-routing traffic to the new build...
         14:34:38.031666: [www.0] Successfully installed build revision rsync-1371306712243 for service  (www) instance #0
         14:34:38.039928: [www.0] Installation successful for service (www) instance #0
         14:34:38.043176: --> Application (traveltime) fully installed
    ==> Application is live at http://traveltime-aibistin.dotcloud.com
    [10:34 - 0.20]
    traveltime > 


I then checked the URL http://traveltime-aibistin.dotcloud.com, which gave me an error.

"uWSGI Error
Perl application not found"

So off to the log files to check what went wrong.

 traveltime > dotcloud logs www
[www.0] ==> /var/log/supervisor/supervisord.log <==
...
cloud/rsync-1371314776610/traveltime/config.conf: Cannot load /home/dotcloud/rsync-1371314776610/traveltime/config.conf: required support modules are not available.
[www.0] Please install Config::General at /home/dotcloud/perl5/lib/perl5/Dancer2/Core/Role/Config.pm line 97
[www.0]  at (eval 35) line 19
[www.0] BEGIN failed--compilation aborted at bin/app.pl line 3.
...
[www.0] ==> /var/log/nginx/access.log <==

So it looks like dotCloud couldn’t find Config::General CPAN module. It looks like I didn’t do such a good job managing my modules dependencies. I could have used the Behemoth of Module creation Dist::Zilla to do this. However as this is not an app that I wish to upload to CPAN, or install on my laptop I wanted an easier way.

I came across this new “Bundle I searched the CPANfor another way. r for Perl” developed by the prolific and excellent Pearl developer Tatsuhiko Miyagawa. So I figured it must be good. And it is. I won’t bore you with the details here, as you can read his documentation yourself.

I now seem to have all my dependencies in order and I ran the “dotcloud push” command again. I ran into another problem. I was running Perl 5.12 on my Ubuntu laptop, and dotCloud needs at least Perl 5.14. Well I guess it was about time that I upgraded my Perl version. This took a while, as I decided to load perlbrew to manage my Perl installations.

I ran into a few glitches here and there, but I finally got it working with lots of help from KENTNL’s perlbrew blog,and a little help from DA Golden’s blog.
So, it’s time to try again from scratch.


traveltime > dotcloud destroy
    Destroy the application "traveltime"? [y/N]: y
    ==> Destroying "traveltime"


dotcloud create traveltime
    ==> Creating a live application named "traveltime"
    ==> Application "traveltime" created.
    Connect the current directory to "traveltime"? [Y/n]: y
    ==> Connecting with the application "traveltime"
    ==> Connected with default push options: --rsync

OK, looking good so far. Now, I have my dotCloud “traveltime” application up and running. I’m not too happy with the domain name that I have been issued by dotCloud, “http://traveltime-aibistin.dotcloud.com”.
So, I decided to change this to one that I already have.


TravelTime > dotcloud domain add www www.carryonmoving.net
    ==> domain "www.carryonmoving.net" created for "www"
    ==> Now please add the following DNS record:
        www.carryonmoving.net. IN CNAME gateway.dotcloud.com.

Then update my DNS settings on CloudFlare and I’m done.

The “finished” (well almost) App Moving Company Travel Time Calculator can be viewed here.

Useful Links

This is where I got lots of helpful advice for this endeavour.

  1. dotCloud Perl Tutorial
  2. Dancer2 Deployment With dotCloud
  3. Marco Fontani’s Dancer Deployment with dotCloud piece, on blogs.perl.org
  4. Perl Mongers dotCloud Presentation (which I just found)
  5. Phillip Smith’s Catalyst with dotCloud piece, on blogs.perl.org

New York City Household Furniture Moving Travel Time Calculator

My next project is to create a travel time calculator application using Dancer2. Hopefully, this would be useful to any household furniture moving company operating in New York City.
When charging for the travel time between two locations, many New York City Moving companies use the following DOT guidelines.

  1. 1/2 an hour within any borough.
  2. 3/4 an hour from one borough to another.
  3. 1 hour for the first 20 miles between locations that either start or end within New York City
  4. 1 hour for each 40 miles after the first 20 miles, which is equivalent to 15 minutes for each 10 miles.

Most of the information that I need to get the distances between locations is freely available from Google’s Distance Matrix API. I checked out CPAN to see if there was a suitable module available to access this API. There were some that partially did what I required, but not all of what I required.
I decided to write my own, which you can read about here.

Forms:

Form To Input Addresses

There are two methods of User Input that I wanted to experiment with. The first is by means of a form where you would enter the exact origin and destination addresses. I describe this in detail here.
The second method, using jQuery autocomplete, I discuss here.

Dancer2 Application TravelTime

The Perl App that implements the Travel Time Calculator

I used the Perl Dancer2 framework for building this application. Dancer2 bills itself as a “Lightweight yet powerful web application framework”, which I guess is true. It works well for me and is not too complex. I did run into a few bugs which seem to have been ironed out in the very latest version. So, it does have an active group of developers who are maintaining and upgrading this software. Thank you for that.
Here is an excerpt from this module, showing one particular route handler. This particular one handles an Ajax call to provide a list of cities that match a specific search criteria. The Dancer2::Plugin::Ajax helps out with this method. The caller in this case is a JavaScript program that I use to implement a jQuery autocomplete input field. You can read about this here

#-------------------------------------------------------------------------------
#    Get a list of city, states and counties.
#-------------------------------------------------------------------------------
ajax '/city_states' => sub {
    
    #------ Trim  whitespace from lhs and append the '%' SQL match char.
    #       This will handle searches like 'Sunn,      New York' (Sunnyside, New York)
    #       or                             'Kew Gar,      New York' (Kew Gardens,  New York)
    #       or                             'Kew,New York'
    my @find_params =
      map { $_ =~ s/^\s+//; s/\s+\z//; $_ . '%' }
      split( ',', params->{find} );
    debug 'The find params array now contains : ' . dump @find_params;

    my $csc_arr;

    #------ Allow some short cuts for the Big Apple
    if ( $find_params[0] =~ /^(nyc|manhattan|base)%\z/i ) {
        $csc_arr->[0] = [ 'New York City', 'New York', 'New York County' ];
    }
    else {

        #----- Search DB for City and Counties matching the search params.
        connect_to_cities() unless $DBH;
        process_error( { Error => 'Unable to connect to the City, State,
                county database! Please try later!', } ) unless $DBH;
        $csc_arr = select_city_state_cty( $DBH, \@find_params );
    }

    #------ Returns sorted list of Cities, States and Counties to
    #       city-states.js
    { city_states => $csc_arr };
};

Have a look at the entire Application code on GitHub.
For a live demo, here is the Moving Truck Travel Time Calculator application running on the dotCloud hosting service.
This is how I deployed my Dancer2 Application to dotCloud.

Creating a Repeatable Address Form with HTML::FormHandler

This is a summary of how I created a repeatable Address Form Module, Mover::Form::Travel::Matrix, using HTML::FormHandler.

As part of my TravelTime Application project I needed to create a form to enter multiple location addresses. I could construct the form manually using Template Toolkit, but I would still need to write my own validation and JavaScript to implement the multiple form requirement.
I could have used HTML::FormFU I have used this previously(much to my regret) to build more complex forms. Not that HTML::FormFu isn’t useful. Once it is mastered it can be a great tool for building many types of complex forms. For me, I found that the learning curve was much too steep and the documentation was dispersed widely amongst many modules. I am sure that this has been improved in recent times, but I really don’t want to go back to pouring through reams of docs for this project.
So I continued on my quest to use another behemoth of CPAN complexity just to make my life more difficult. I had wanted an excuse to experiment with HTML::Formhandler and this seemed like a good time to do this. The documentation for this makes War And Peace seem like a side note on a shopping list. It must have taken longer to create than the Bible and hopefully will be less contentious. Seemingly it is the work of one developer by the name of Gerda Shank who must have locked herself away in a cave for a millennium to give the Pearl world this form framework.
What I like about HTML::FormHandler is that it seems much more Moose Like and intuitive to anybody who has worked with Moose. It seems very simple at first, however to get the best out of this, the learning curve is steep and requires time. So, say goodbye to family and social life while you get familiar with HTML::FormHandler.

FormHandler Forms

Mover::Form::Field::Address

Before I make my repeatable address form, I created a form element for any US address using a FormHandler Moose Role. This is one of the many useful things about HTML::Formhandler. You can create many building blocks which can be used again and again. Here is the module on github Mover::Form::Field::Address

.....

use HTML::FormHandler::Types qw/Zip Trim Collapse/;

has_field 'address_1' => (
    is      => 'rw', 
    isa     => Collapse, 
    required => 0,
    message  => {
        required => 'You must enter a street address!'
    }
);
has_field 'address_2' => (is => 'rw', isa => Collapse);
has_field 'city' => (is => 'rw', isa => Collapse);
has_field 'state' => ( type => 'Select', options_method => \&_options_state );
has_field 'country' => (is => 'rw', isa => Collapse);
#------ Create Zip Field Type
has_field 'zip' => ( is => 'rw',  isa => Zip);
#------------------------------------------------------------------------------
=head2 options_state
  Builds the Options for US states. (NY New York,  AL Alabama etc).
  Note: It does not include "DC". I may add DC later just as an alternative.
=cut

sub _options_state {

    return (
        'AL' => 'Alabama',
        'AK' => 'Alaska',
        'AZ' => 'Arizona',
         ...
        'WY' => 'Wyoming',
    );

}

no HTML::FormHandler::Moose::Role;
1;

When I initially created this Role, I had intended to manually validate the Zip Code field using Regexp::Common. I then found that FormHandler has a types Module with some useful stuff in there, including a zip code. I will try this out instead. It also has types to trim off extra white space. How convenient.

Mover::Form::Travel::Matrix

This is the actual HTML::FormHandler form, which has repeatable Address elements. I also opted to include some of the convenient FormHandler Widgets that were created to make use of the Twitter Bootstrap CSS framework. There’s lots of stuff available with HTML::FormHandler.
This module is available here on GitHub Mover::Form::Travel::Matrix


has '+field_name_space' => ( default => 'Mover::Form::Field' );
 
has '+name'        => ( default => $form_name );
 
has '+html_prefix' => ( default => 1 );
 
has '+is_html5'    => ( default => 1 );
 
has '+http_method' => ( default => $http_method );
 
has '+action'      => ( default => $form_action );

#----- Mover::Form::Field::Address that is Repeatable
 
has_field 'addresses' => (
    type         => 'Repeatable',
    setup_for_js => 1,
    do_wrapper   => 1,
    tags         => { controls_div => 1 },
    auto_id      => 1,
);

has_field 'addresses.contains' => ( type => 'Address', );
 
has_field 'submit' => (
    type         => 'Submit',
    widget       => 'ButtonTag',
    element_attr => { class => [ 'btn', $button_class, $button_size ] },
    do_wrapper   => 0,
    value        => 'Get Travel Time'
);
 
has '+info_message'    => ( default => 'Starting point.' );
 
has '+success_message' => ( default => 'Form successfully submitted' );

has '+error_message'   => ( default => 'Please fix the errors on this form!' );

Now, we have a form with a repeatable address field and some fancy Bootstrap CSS, Yippee!
Next up is to create some templates to render the form pages. So, I will use the now familiar Template Toolkit to do this.

The Address Form Template

travel_time.tt

<!-- Travel Matrix Form -->
<form name="[% tm_form.name %]" id="[% tm_form.name %]"
  action="[% tm_form.action %]" method="[% tm_form.http_method %]"
  class="form-vertical" >


<fieldset >
   <legend>
      <p class="lead">
         [%- 
             travel_time_heading 
             || 'Calculate Moving Truck Travel Time'
         -%]
      </p>
   </legend>

<!--  Start messages -->
    <div id="messages">
    <p class="text-success">[%- success_message -%]</p>
    <p class="text-error">[%- error_message -%]</p>
    <p class="text-warning">[%- warning_message -%]</p>
    <p class="text-info">[%- info_message  -%]</p>
    </div>
<!-- End  messages -->

    [% started_new_row  = 0  %]  [%# To specify how many Addresses per line %]
    <!--- four to a line -->
    [% FOREACH address_element IN tm_form.field('addresses').fields -%]
        [%  IF ((loop.count == 1) || ((loop.count % 5) == 0))   %]

          [% IF ( started_new_row == 1) %]
              <!-- Close previous row before opening a new one. -->
               </div> <!-- /row-fluid -->
          [%  END %]
          <div class="row-fluid">
          [% started_new_row  = 1 %]
        [% END %]

        <div class="span3 well">
        
          [% IF loop.first %]
              <span class="text-info">
                <abbr title='Calculations are based from a starting point in central New York City.'>
                First Address
                </abbr>
              </span>
          [% ELSIF loop.last  %] 
              <span class="text-info">
                  <abbr title='The next version will have an option for more destination points.'>
                  Last Address</abbr>
              </span>

          [% ELSE %]
              <span class='text-info'>Address [% loop.count %]</span>
          [% END %]
          
          [% address_element.render %]

        </div> <!-- /span3 -->
    [% END %]

    [% IF ( started_new_row == 1) %] [%# Close div tag at end of each row %]
        </div> <!-- /row-fluid -->
        [% started_new_row  = 0 %]
    [%  END %]



<div class="row-fluid">
    [% tm_form.field('submit').render %]
</div> <!-- /row-fluid -->
</fieldset>
</form>

</div> <!-- /row-fluid -->

[% IF ( tm_form.is_valid) %]

    [% IF (my_errors) %]
        <div class="alert alert-error">
        <span><b>[% error_message  || 'What a mess!' %]</b></span>
        [%# One way to loop through a hash %]
        [% FOREACH error IN my_errors.values %]
         <span> [% error %]</span>
         [% END %]
        </div>
    [%  END %]
    
[% ELSIF ( tm_form.errors) %]
    <div class="alert alert-error row-fluid">
        [% FOREACH error IN tm_form.errors -%]
        <span class="span2">[% error %]</span>
        [% END %]
    </div>
[%  END %]

The source code for this template is available here.
There are many other ways to render a HTML::Formhandler form, which you can explore in the CPAN documentation.

There is much to explore in HTML::FormHandler and I am sure I will be using it again in future projects.