/** 
 *  ====================================================================
 *    Library of jQuery plugins used globally througout the template.
 *
 *    TABLE OF CONTENTS
 *    01 - prettyPhotoHover - addition to the Pretty Photo plugin
 *    02 - pragmaNavigation - navigation with multi-level drop-downs
 *    03 - in-Field label jQuery plugin
 *    04 - jQuery easing functions
 *    05 - jQuery form validation plugin
 *  ====================================================================
 */



/**
 *  ================================================================
 *  02 - pragmaNavigation - navigation with multi-level drop-downs
 *  ================================================================
 */
jQuery.fn.pragmaNavigation = function(conf) {

  conf = jQuery.extend({
    initialSubnavZIndex: 1000,          // zIndex for the 1st subnav, subsequent subnavs get incremental values
    slideDownSpeed: 400,                // time of the slide-down animation in miliseconds
    slideUpSpeed: 200,                  // time of the slide-up animation in miliseconds
    slideDownEffect: 'easeOutBounce',   // name of the easing function (look at the easing functions at the bottom of this file)
    slideUpEffect: 'easeOutQuart',      // name of the easing function (look at the easing functions at the bottom of this file)
    eventTimeoutTime: 200,              // delay before a mouse event is actioned
    subnavL1offsetTop: 50,              // distance of level 1 drop-down from the main nav link
    subnavL1offsetLeft: 0,
    subnavsOffsetTop: -16,              // distance of the child drop-down from the parent link
    subnavsOffsetLeft: 10,
    contentWidth: 960,                  // total width of the content area in pixels - used to decide whether a drop-down should be displayed on the right or left
    contentBoundryTolerance: 20,        // related to the above - sets how far the drop-downs can move outside the content area
    pointerDownImgNormal: 'img/silver/blue/drop-down-icon.png',    // drop-down indicator images URL's
    pointerDownImgeHover: 'img/silver/blue/drop-down-icon-hover.png',
    pointerRightImgNormal: 'img/silver/blue/arrow-list.gif',
    pointerRightImgeHover: 'img/silver/blue/arrow-list-hover.gif',
    pointerDownPosTop: 18,            // drop-down indicator images positions
    pointerDownPosRight: 10,
    pointerDownWidth: 15,
    pointerDownHeight: 16,
    pointerRightPosTop: 6,
    pointerRightPosLeft: 153
  }, conf);

  return this.each(function() {
    var nav = jQuery(this);
    var jqd = jQuery.data;
    var zIndex = conf.initialSubnavZIndex;
    var itemIndex = 0;
    var subnavIndex = 0;
    var level = 0;
    var parentItemUIDs = false;
    var parentSubnavUIDs = false;
    var items = new Object();
    var subnavs = new Object();
    var timeouts = new Object();
    
    nav.find('ul.level-1').wrap('<div class="main-nav-subnav level-1"></div>');
    nav.find('ul.level-n').wrap('<div class="main-nav-subnav level-n"></div>');
    
    makeDropDowns(nav);
     
    function makeDropDowns (navLevel) {
      var levelItems = navLevel.children('ul').children('li');
      levelItems.each(function(i){
        var item = jQuery(this);
        
        itemIndex++;
        var itemUID = 'item_'+itemIndex;
        jqd(item,'UID',itemUID);
        jqd(item,'level',level);
        items[itemUID] = item;
        
        if (item.find('ul.subnav-list').size()>0) { // If item has subnav
          // Add subnav indicators
          if (level == 0) {
            var pointerDown = jQuery('<img/>')
                .attr({'src':getPointerImgSrc(level,'normal'),'width':conf.pointerDownWidth,'height':conf.pointerDownHeight})
                .css({'position':'absolute', 'top':conf.pointerDownPosTop, 'right':conf.pointerDownPosRight});
            item.children('a').addClass('has-subnav').append(pointerDown);
          } else {
            var pointerRight = jQuery('<img/>')
                .attr({'src':getPointerImgSrc(level,'normal')})
                .css({'display':'block','position':'absolute','top':conf.pointerRightPosTop,'left':conf.pointerRightPosLeft});
            item.children('a').prepend(pointerRight);
          }
          var subnav = item.children('div.main-nav-subnav');
          
          subnavIndex++;
          var subnavUID = 'sub_'+subnavIndex;
          jqd(item,'subnavUID',subnavUID);
          jqd(subnav,'UID',subnavUID);
          
          var level__tmp = level; level++;
          jqd(subnav,'level',level);
          
          var parentItemUIDs__tmp = parentItemUIDs;
          parentItemUIDs = ( parentItemUIDs ? parentItemUIDs+'|'+itemUID : itemUID );
          jqd(subnav,'parentItemUIDs',parentItemUIDs);
          
          jqd(subnav,'parentSubnavUIDs',parentSubnavUIDs);
          var parentSubnavUIDs__tmp = parentSubnavUIDs;
          parentSubnavUIDs = ( parentSubnavUIDs ? parentSubnavUIDs+'|'+subnavUID : subnavUID );
          
          subnavs[subnavUID] = subnav;
          initializeSubnav(item,subnav)
          itemAddMouseEvents(item,subnav);
          subnavAddMouseEvents(subnav);
          makeDropDowns(subnav);
          
          level = level__tmp; parentSubnavUIDs = parentSubnavUIDs__tmp; parentItemUIDs = parentItemUIDs__tmp;
        }
      });
    }
    
    function itemAddMouseEvents(item,subnav) {
      item.mouseenter(function(){
        var itemTimeoutKey = jqd(item,'UID');
        if (timeouts[itemTimeoutKey]) {
          clearTimeout(timeouts[itemTimeoutKey]);
        } else {
          item.addClass('item-hover');
          item.children('a').children('img').attr({'src':getPointerImgSrc(jqd(item,'level'),'hover')});
        }
        var subnavTimeoutKey = jqd(subnav,'UID');
        if (timeouts[subnavTimeoutKey]) {
          clearTimeout(timeouts[subnavTimeoutKey]);
        } else {
          positionSubnav(item,subnav);
          subnav.animate({height: "show"}, conf.slideDownSpeed, conf.slideDownEffect);
        }
      }).mouseleave(function(){
        var itemTimeout = setItemTimeout(item);
        var subnavTimeout = setSubnavTimeout(subnav);
        timeouts[ jqd(item,'UID') ] = itemTimeout;
        timeouts[ jqd(subnav,'UID') ] = subnavTimeout;
      });
    }
    
    function subnavAddMouseEvents(subnav) {
      subnav.mouseenter(function(){
        var parentItemUIDs = parentItems(subnav);
        for (var i=0; i < parentItemUIDs.length; i++) {
          var parentItemUID = parentItemUIDs[i];
          if (timeouts[parentItemUID]) { clearTimeout(timeouts[parentItemUID]); }
        }
        if (parentSubnavs(subnav)) {
          var parentSubnavUIDs = parentSubnavs(subnav);
          for (var i=0; i < parentSubnavUIDs.length; i++) {
            var parentSubnavUID = parentSubnavUIDs[i];
            clearTimeout(timeouts[parentSubnavUID]);
          }
        }
        if (timeouts[ jqd(subnav,'UID') ]) { clearTimeout(timeouts[ jqd(subnav,'UID') ]); }
      }).mouseleave(function(){
        var subnavTimeout = setSubnavTimeout(subnav);
        timeouts[ jqd(subnav,'UID') ] = subnavTimeout;
        var parentItemUIDs = parentItems(subnav);
        for (var i=0; i < parentItemUIDs.length; i++) {
          var parentItemUID = parentItemUIDs[i];
          var item = items[parentItemUID];
          var itemTimeout = setItemTimeout(item);
          timeouts[parentItemUID] = itemTimeout;
        }
        if (parentSubnavs(subnav)) {
          var parentSubnavUIDs = parentSubnavs(subnav);
          for (var i=0; i < parentSubnavUIDs.length; i++) {
            var parentSubnavUID = parentSubnavUIDs[i];
            var parentSubnav = subnavs[parentSubnavUID];
            var subnavTimeout = setSubnavTimeout(parentSubnav);
            timeouts[parentSubnavUID] = subnavTimeout;
          }
        }
      }); 
    }
    
    function  getPointerImgSrc (level,state) {
      if (level == 0) {
        if (state == 'hover') { return conf.pointerDownImgeHover; } else { return conf.pointerDownImgNormal; }
      } else {
        if (state == 'hover') { return conf.pointerRightImgeHover; } else { return conf.pointerRightImgNormal; }
      }
    }
    
    function parentItems (subnav) {
      return jqd(subnav,'parentItemUIDs').split('|');
    }
    
    function parentSubnavs (subnav) {
      if (jqd(subnav,'parentSubnavUIDs')) {
        return jqd(subnav,'parentSubnavUIDs').split('|');
      } else {
        return false;
      }
    }
    
    function setItemTimeout (item) {
      function timeoutFunc() {
        timeouts[jqd(item,'UID')] = undefined;
        item.removeClass('item-hover');
        item.children('a').children('img').attr({'src':getPointerImgSrc(jqd(item,'level'),'normal')});
      }
      return setTimeout(timeoutFunc, conf.eventTimeoutTime);
    }
    
    function setSubnavTimeout (subnav) {
      function timeoutFunc() {
        timeouts[jqd(subnav,'UID')] = undefined;
        subnav.animate({height: "hide"}, conf.slideUpSpeed, conf.slideUpEffect);

      }
      return setTimeout(timeoutFunc, conf.eventTimeoutTime);
    }
    
    function initializeSubnav (item,subnav) {
      subnav.remove().prependTo('body').css({ 'z-index':zIndex }).hide().children('ul.subnav-list').css('display','block');
      zIndex++;
    }
    
    function positionSubnav(item,subnav) {
      var itemPos = item.offset();
      var itemWidth = item.outerWidth();
      var subnavWidth = subnav.outerWidth();
      if (jqd(subnav,'level') == 1) {
        var itemPosTop = itemPos.top + conf.subnavL1offsetTop; var itemPosLeft = itemPos.left + conf.subnavL1offsetLeft;
      } else {
        var itemPosTop = itemPos.top + conf.subnavsOffsetTop; var itemPosLeft = itemPos.left + itemWidth + conf.subnavsOffsetLeft;
        if ( (itemPosLeft + subnavWidth) > (contentBoundryRight()) ) {
          itemPosLeft = itemPos.left - subnavWidth - conf.subnavsOffsetLeft;
        }
      }
      
      subnav.css({ top: itemPosTop, left: itemPosLeft });
    }
    
    function contentBoundryRight(){
      var contentWidth = conf.contentWidth + (conf.contentBoundryTolerance * 2);
      var windowWidth = jQuery(window).width();
      if (windowWidth < contentWidth) {
        return windowWidth;
      } else {
        return ((windowWidth-contentWidth)/2)+contentWidth;
      }
    }
    
  });
}


/*
 *  ================================================================
 *  03 - In-Field Label jQuery Plugin
 *  http://fuelyourcoding.com/in-field-labels/
 *
 *  Copyright (c) 2009 Doug Neiner
 *  Dual licensed under the MIT and GPL licenses.
 *  Uses the same license as jQuery, see:
 *  http://docs.jquery.com/License
 *
 *  @version 0.1
 *  ================================================================
 */
jQuery(function($){
  
    $.InFieldLabels = function(label,field, options){
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;
        
        // Access to jQuery and DOM versions of each element
        base.$label = $(label);
        base.label = label;

     base.$field = $(field);
    base.field = field;
        
    base.$label.data("InFieldLabels", base);
    base.showing = true;
        
        base.init = function(){
      // Merge supplied options with default options
            base.options = $.extend({},$.InFieldLabels.defaultOptions, options);

      // Check if the field is already filled in
      if(base.$field.val() != ""){
        base.$label.hide();
        base.showing = false;
      };
      
      base.$field.focus(function(){
        base.fadeOnFocus();
      }).blur(function(){
        base.checkForEmpty(true);
      }).bind('keydown.infieldlabel',function(e){
        // Use of a namespace (.infieldlabel) allows us to
        // unbind just this method later
        base.hideOnChange(e);
      }).change(function(e){
        base.checkForEmpty();
      }).bind('onPropertyChange', function(){
        base.checkForEmpty();
      });
        };

    // If the label is currently showing
    // then fade it down to the amount
    // specified in the settings
    base.fadeOnFocus = function(){
      if(base.showing){
        base.setOpacity(base.options.fadeOpacity);
      };
    };
    
    base.setOpacity = function(opacity){
      base.$label.stop().animate({ opacity: opacity }, base.options.fadeDuration);
      base.showing = (opacity > 0.0);
    };
    
    // Checks for empty as a fail safe
    // set blur to true when passing from
    // the blur event
    base.checkForEmpty = function(blur){
      if(base.$field.val() == ""){
        base.prepForShow();
        base.setOpacity( blur ? 1.0 : base.options.fadeOpacity );
      } else {
        base.setOpacity(0.0);
      };
    };
    
    base.prepForShow = function(e){
      if(!base.showing) {
        // Prepare for a animate in...
        base.$label.css({opacity: 0.0}).show();
        
        // Reattach the keydown event
        base.$field.bind('keydown.infieldlabel',function(e){
          base.hideOnChange(e);
        });
      };
    };

    base.hideOnChange = function(e){
      if(
        (e.keyCode == 16) || // Skip Shift
        (e.keyCode == 9) // Skip Tab
        ) return; 
      
      if(base.showing){
        base.$label.hide();
        base.showing = false;
      };
      
      // Remove keydown event to save on CPU processing
      base.$field.unbind('keydown.infieldlabel');
    };
      
    // Run the initialization method
        base.init();
    };
  
    $.InFieldLabels.defaultOptions = {
        fadeOpacity: 0.5, // Once a field has focus, how transparent should the label be
    fadeDuration: 300 // How long should it take to animate from 1.0 opacity to the fadeOpacity
    };
  

    $.fn.inFieldLabels = function(options){
        return this.each(function(){
      // Find input or textarea based on for= attribute
      // The for attribute on the label must contain the ID
      // of the input or textarea element
      var for_attr = $(this).attr('for');
      if( !for_attr ) return; // Nothing to attach, since the for field wasn't used
      
      
      // Find the referenced input or textarea element
      var $field = $(
        "input#" + for_attr + "[type='text']," + 
        "input#" + for_attr + "[type='password']," + 
        "textarea#" + for_attr
        );
        
      if( $field.length == 0) return; // Again, nothing to attach
      
      // Only create object for input[text], input[password], or textarea
            (new $.InFieldLabels(this, $field[0], options));
        });
    };
  
});

/**
 *  ================================================================
 *  04 - jQuery easing functions
 *
 *  jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
 *
 *  Uses the built in easing capabilities added In jQuery 1.1
 *  to offer multiple easing options
 *
 *  TERMS OF USE - jQuery Easing
 * 
 *  Open source under the BSD License. 
 * 
 *  Copyright © 2008 George McGinley Smith
 *  All rights reserved.
 * 
 *  Redistribution and use in source and binary forms, with or without modification, 
 *  are permitted provided that the following conditions are met:
 * 
 *  Redistributions of source code must retain the above copyright notice, this list of 
 *  conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright notice, this list 
 *  of conditions and the following disclaimer in the documentation and/or other materials 
 *  provided with the distribution.
 * 
 *  Neither the name of the author nor the names of contributors may be used to endorse 
 *  or promote products derived from this software without specific prior written permission.
 * 
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 *  OF THE POSSIBILITY OF SUCH DAMAGE. 
 *  ================================================================
*/

// t: current time, b: begInnIng value, c: change In value, d: duration
jQuery.easing['jswing'] = jQuery.easing['swing'];

jQuery.extend( jQuery.easing,
{
  def: 'easeOutQuad',
  swing: function (x, t, b, c, d) {
    //alert(jQuery.easing.default);
    return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
  },
  easeInQuad: function (x, t, b, c, d) {
    return c*(t/=d)*t + b;
  },
  easeOutQuad: function (x, t, b, c, d) {
    return -c *(t/=d)*(t-2) + b;
  },
  easeInOutQuad: function (x, t, b, c, d) {
    if ((t/=d/2) < 1) return c/2*t*t + b;
    return -c/2 * ((--t)*(t-2) - 1) + b;
  },
  easeInCubic: function (x, t, b, c, d) {
    return c*(t/=d)*t*t + b;
  },
  easeOutCubic: function (x, t, b, c, d) {
    return c*((t=t/d-1)*t*t + 1) + b;
  },
  easeInOutCubic: function (x, t, b, c, d) {
    if ((t/=d/2) < 1) return c/2*t*t*t + b;
    return c/2*((t-=2)*t*t + 2) + b;
  },
  easeInQuart: function (x, t, b, c, d) {
    return c*(t/=d)*t*t*t + b;
  },
  easeOutQuart: function (x, t, b, c, d) {
    return -c * ((t=t/d-1)*t*t*t - 1) + b;
  },
  easeInOutQuart: function (x, t, b, c, d) {
    if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
    return -c/2 * ((t-=2)*t*t*t - 2) + b;
  },
  easeInQuint: function (x, t, b, c, d) {
    return c*(t/=d)*t*t*t*t + b;
  },
  easeOutQuint: function (x, t, b, c, d) {
    return c*((t=t/d-1)*t*t*t*t + 1) + b;
  },
  easeInOutQuint: function (x, t, b, c, d) {
    if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
    return c/2*((t-=2)*t*t*t*t + 2) + b;
  },
  easeInSine: function (x, t, b, c, d) {
    return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
  },
  easeOutSine: function (x, t, b, c, d) {
    return c * Math.sin(t/d * (Math.PI/2)) + b;
  },
  easeInOutSine: function (x, t, b, c, d) {
    return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
  },
  easeInExpo: function (x, t, b, c, d) {
    return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
  },
  easeOutExpo: function (x, t, b, c, d) {
    return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
  },
  easeInOutExpo: function (x, t, b, c, d) {
    if (t==0) return b;
    if (t==d) return b+c;
    if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
    return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
  },
  easeInCirc: function (x, t, b, c, d) {
    return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
  },
  easeOutCirc: function (x, t, b, c, d) {
    return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
  },
  easeInOutCirc: function (x, t, b, c, d) {
    if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
    return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
  },
  easeInElastic: function (x, t, b, c, d) {
    var s=1.70158;var p=0;var a=c;
    if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
    if (a < Math.abs(c)) { a=c; var s=p/4; }
    else var s = p/(2*Math.PI) * Math.asin (c/a);
    return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
  },
  easeOutElastic: function (x, t, b, c, d) {
    var s=1.70158;var p=0;var a=c;
    if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
    if (a < Math.abs(c)) { a=c; var s=p/4; }
    else var s = p/(2*Math.PI) * Math.asin (c/a);
    return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
  },
  easeInOutElastic: function (x, t, b, c, d) {
    var s=1.70158;var p=0;var a=c;
    if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
    if (a < Math.abs(c)) { a=c; var s=p/4; }
    else var s = p/(2*Math.PI) * Math.asin (c/a);
    if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
    return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
  },
  easeInBack: function (x, t, b, c, d, s) {
    if (s == undefined) s = 1.70158;
    return c*(t/=d)*t*((s+1)*t - s) + b;
  },
  easeOutBack: function (x, t, b, c, d, s) {
    if (s == undefined) s = 1.70158;
    return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
  },
  easeInOutBack: function (x, t, b, c, d, s) {
    if (s == undefined) s = 1.70158; 
    if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
    return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
  },
  easeInBounce: function (x, t, b, c, d) {
    return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
  },
  easeOutBounce: function (x, t, b, c, d) {
    if ((t/=d) < (1/2.75)) {
      return c*(7.5625*t*t) + b;
    } else if (t < (2/2.75)) {
      return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
    } else if (t < (2.5/2.75)) {
      return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
    } else {
      return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
    }
  },
  easeInOutBounce: function (x, t, b, c, d) {
    if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
    return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
  }
});

/*
 *  ================================================================
 *  TERMS OF USE - EASING EQUATIONS
 * 
 *  Open source under the BSD License. 
 *
 *  Copyright © 2001 Robert Penner
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without modification, 
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list of 
 *  conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright notice, this list 
 *  of conditions and the following disclaimer in the documentation and/or other materials 
 *  provided with the distribution.
 * 
 *  Neither the name of the author nor the names of contributors may be used to endorse 
 *  or promote products derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 *  OF THE POSSIBILITY OF SUCH DAMAGE. 
 *  ================================================================
 */


