var env = 'production';
;(function($) {
  $.fix_ie_disabled_options = function() {
    if (!$.browser.msie) { return; }
    $('select').each(function(){
      this.rejectDisabled = function(){
        if (this.selectedIndex >= 0 &&
            this.options[this.selectedIndex].disabled){
          if (this.lastSelectedIndex) {
            this.selectedIndex = this.lastSelectedIndex;
          } else {
            var first_enabled =
              $(this).children('option:not(:disabled)').get(0);
            this.selectedIndex = first_enabled ? first_enabled.index : 0;
          }
        } else {
          this.lastSelectedIndex = this.selectedIndex;
        }
      };
      this.rejectDisabled();
      this.lastSelectedIndex = this.selectedIndex;
      $(this).children('option:not(:disabled)').each(function() {
        $(this).css('color', '');
      });
      $(this).children('option[disabled]').each(function(){
        $(this).css('color', '#CCC');

      });
      $(this).change(function() {
        this.rejectDisabled();
        $('#searchcontainer').click();
      });
    });
  };
})(jQuery);
this.JS=this.JS||{};JS.extend=function(a,b){b=b||{};for(var c in b){if(a[c]===b[c])continue;a[c]=b[c]}return a};JS.extend(JS,{makeFunction:function(){return function(){return this.initialize?(this.initialize.apply(this,arguments)||this):this}},makeBridge:function(a){var b=function(){};b.prototype=a.prototype;return new b},bind:function(){var a=JS.array(arguments),b=a.shift(),c=a.shift()||null;return function(){return b.apply(c,a.concat(JS.array(arguments)))}},callsSuper:function(a){return a.SUPER===undefined?a.SUPER=/\bcallSuper\b/.test(a.toString()):a.SUPER},mask:function(a){var b=a.toString().replace(/callSuper/g,'super');a.toString=function(){return b};return a},array:function(a){if(!a)return[];if(a.toArray)return a.toArray();var b=a.length,c=[];while(b--)c[b]=a[b];return c},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},isFn:function(a){return a instanceof Function},isType:function(a,b){if(!a||!b)return false;return(b instanceof Function&&a instanceof b)||(typeof b==='string'&&typeof a===b)||(a.isA&&a.isA(b))},ignore:function(a,b){return/^(include|extend)$/.test(a)&&typeof b==='object'}});JS.Module=JS.makeFunction();JS.extend(JS.Module.prototype,{END_WITHOUT_DOT:/([^\.])$/,initialize:function(a,b,c){this.__mod__=this;this.__inc__=[];this.__fns__={};this.__dep__=[];this.__mct__={};if(typeof a==='string'){this.__nom__=this.displayName=a}else{this.__nom__=this.displayName='';c=b;b=a}c=c||{};this.__res__=c._1||null;if(b)this.include(b,false);if(JS.Module.__chainq__)JS.Module.__chainq__.push(this)},setName:function(a){this.__nom__=this.displayName=a||'';for(var b in this.__mod__.__fns__)this.__name__(b);if(a&&this.__meta__)this.__meta__.setName(a+'.')},__name__:function(a){if(!this.__nom__)return;var b=this.__mod__.__fns__[a]||{};a=this.__nom__.replace(this.END_WITHOUT_DOT,'$1#')+a;if(JS.isFn(b.setName))return b.setName(a);if(JS.isFn(b))b.displayName=a},define:function(a,b,c,d){var f=(d||{})._0||this;this.__fns__[a]=b;this.__name__(a);if(JS.Module._0&&f&&JS.isFn(b))JS.Module._0(a,f);if(c!==false)this.resolve()},instanceMethod:function(a){var b=this.lookup(a).pop();return JS.isFn(b)?b:null},instanceMethods:function(a,b){var c=this.__mod__,b=b||[],d=c.ancestors(),f=d.length,e;for(e in c.__fns__){if(c.__fns__.hasOwnProperty(e)&&JS.isFn(c.__fns__[e])&&JS.indexOf(b,e)===-1)b.push(e)}if(a===false)return b;while(f--)d[f].instanceMethods(false,b);return b},include:function(a,b,c){b=(b!==false);if(!a)return b?this.resolve():this.uncache();c=c||{};if(a.__mod__)a=a.__mod__;var d=a.include,f=a.extend,e=c._4||this,g,h,i,j;if(a.__inc__&&a.__fns__){this.__inc__.push(a);a.__dep__.push(this);if(c._2)a.extended&&a.extended(c._2);else a.included&&a.included(e)}else{if(c._5){for(h in a){if(JS.ignore(h,a[h]))continue;this.define(h,a[h],false,{_0:e||c._2||this})}}else{if(typeof d==='object'||JS.isType(d,JS.Module)){g=[].concat(d);for(i=0,j=g.length;i<j;i++)e.include(g[i],b,c)}if(typeof f==='object'||JS.isType(f,JS.Module)){g=[].concat(f);for(i=0,j=g.length;i<j;i++)e.extend(g[i],false);e.extend()}c._5=true;return e.include(a,b,c)}}b?this.resolve():this.uncache()},includes:function(a){var b=this.__mod__,c=b.__inc__.length;if(Object===a||b===a||b.__res__===a.prototype)return true;while(c--){if(b.__inc__[c].includes(a))return true}return false},match:function(a){return a.isA&&a.isA(this)},ancestors:function(a){var b=this.__mod__,c=(a===undefined),d=(b.__res__||{}).klass,f=(d&&b.__res__===d.prototype)?d:b,e,g;if(c&&b.__anc__)return b.__anc__.slice();a=a||[];for(e=0,g=b.__inc__.length;e<g;e++)b.__inc__[e].ancestors(a);if(JS.indexOf(a,f)===-1)a.push(f);if(c)b.__anc__=a.slice();return a},lookup:function(a){var b=this.__mod__,c=b.__mct__;if(c[a])return c[a].slice();var d=b.ancestors(),f=[],e,g,h;for(e=0,g=d.length;e<g;e++){h=d[e].__mod__.__fns__[a];if(h)f.push(h)}c[a]=f.slice();return f},make:function(a,b){if(!JS.isFn(b)||!JS.callsSuper(b))return b;var c=this;return function(){return c.chain(this,a,arguments)}},chain:JS.mask(function(c,d,f){var e=this.lookup(d),g=e.length-1,h=c.callSuper,i=JS.array(f),j;c.callSuper=function(){var a=arguments.length;while(a--)i[a]=arguments[a];g-=1;var b=e[g].apply(c,i);g+=1;return b};j=e.pop().apply(c,i);h?c.callSuper=h:delete c.callSuper;return j}),resolve:function(a){var b=this.__mod__,a=a||b,c=a.__res__,d,f,e,g;if(a===b){b.uncache(false);d=b.__dep__.length;while(d--)b.__dep__[d].resolve()}if(!c)return;for(d=0,f=b.__inc__.length;d<f;d++)b.__inc__[d].resolve(a);for(e in b.__fns__){g=a.make(e,b.__fns__[e]);if(c[e]!==g)c[e]=g}},uncache:function(a){var b=this.__mod__,c=b.__dep__.length;b.__anc__=null;b.__mct__={};if(a===false)return;while(c--)b.__dep__[c].uncache()}});JS.Class=JS.makeFunction();JS.extend(JS.Class.prototype=JS.makeBridge(JS.Module),{initialize:function(a,b,c){if(typeof a==='string'){this.__nom__=this.displayName=a}else{this.__nom__=this.displayName='';c=b;b=a}var d=JS.extend(JS.makeFunction(),this);d.klass=d.constructor=this.klass;if(!JS.isFn(b)){c=b;b=Object}d.inherit(b);d.include(c,false);d.resolve();do{b.inherited&&b.inherited(d)}while(b=b.superclass);return d},inherit:function(a){this.superclass=a;if(this.__eigen__&&a.__eigen__)this.extend(a.__eigen__(),true);this.subclasses=[];(a.subclasses||[]).push(this);var b=this.prototype=JS.makeBridge(a);b.klass=b.constructor=this;this.__mod__=new JS.Module(this.__nom__,{},{_1:this.prototype});this.include(JS.Kernel,false);if(a!==Object)this.include(a.__mod__||new JS.Module(a.prototype,{_1:a.prototype}),false)},include:function(a,b,c){if(!a)return;var d=this.__mod__,c=c||{};c._4=this;return d.include(a,b,c)},define:function(a,b,c,d){var f=this.__mod__;d=d||{};d._0=this;f.define(a,b,c,d)}});JS.Module=new JS.Class('Module',JS.Module.prototype);JS.Class=new JS.Class('Class',JS.Module,JS.Class.prototype);JS.Module.klass=JS.Module.constructor=JS.Class.klass=JS.Class.constructor=JS.Class;JS.extend(JS.Module,{_3:[],__chainq__:[],methodAdded:function(a,b){this._3.push([a,b])},_0:function(a,b){var c=this._3,d=c.length;while(d--)c[d][0].call(c[d][1]||null,a,b)}});JS.Kernel=JS.extend(new JS.Module('Kernel',{__eigen__:function(){if(this.__meta__)return this.__meta__;var a=this.__nom__,b=this.klass.__nom__,c=a||(b?'#<'+b+'>':''),d=this.__meta__=new JS.Module(c?c+'.':'',{},{_1:this});d.include(this.klass.__mod__,false);return d},equals:function(a){return this===a},extend:function(a,b){return this.__eigen__().include(a,b,{_2:this})},hash:function(){return this.__hashcode__=this.__hashcode__||JS.Kernel.getHashCode()},isA:function(a){return this.__eigen__().includes(a)},method:function(a){var b=this,c=b.__mcache__=b.__mcache__||{};if((c[a]||{}).fn===b[a])return c[a].bd;return(c[a]={fn:b[a],bd:JS.bind(b[a],b)}).bd},methods:function(){return this.__eigen__().instanceMethods(true)},tap:function(a,b){a.call(b||null,this);return this}}),{__hashIndex__:0,getHashCode:function(){this.__hashIndex__+=1;return(Math.floor(new Date().getTime()/1000)+this.__hashIndex__).toString(16)}});JS.Module.include(JS.Kernel);JS.extend(JS.Module,JS.Kernel.__fns__);JS.Class.include(JS.Kernel);JS.extend(JS.Class,JS.Kernel.__fns__);JS.Interface=new JS.Class({initialize:function(d){this.test=function(a,b){var c=d.length;while(c--){if(!JS.isFn(a[d[c]]))return b?d[c]:false}return true}},extend:{ensure:function(){var a=JS.array(arguments),b=a.shift(),c,d;while(c=a.shift()){d=c.test(b,true);if(d!==true)throw new Error('object does not implement '+d+'()');}}}});JS.Singleton=new JS.Class({initialize:function(a,b,c){return new(new JS.Class(a,b,c))}});
;
(function($) {
  $.detect =  function(array, func) {
    var ret = null;
    $.each(array, function(i, o) {
      if (func(o)) {
        ret = o;
        return false;
      }
    });
    return ret;
  };
  $.select_by_bits = function(collection, bit1, bit2) {
    bit1 = (bit1 === true) ? true: Math.pow(2, bit1-1);
    bit2 = (bit2 === true) ? true: Math.pow(2, bit2-1);
    var new_collection = $.find_all(collection, function(o) {
      var agree_bit1 = (bit1 === true) ? true : ((o.hotelbit1 & bit1) > 0);
      var agree_bit2 = (bit2 === true) ? true : ((o.hotelbit2 & bit2) > 0);
      return (agree_bit1 && agree_bit2);
    });
    return new_collection;
  };
  $.find_all =  function(array, func) {
    return $.map(array, function(o) {
      return(func(o) ? o : null);
    });
  };
  $.is_defined = function(object, member) {
    if (typeof(object[member]) === "undefined") {
      return false;
    }
    return true;
  };
  $.quoteString = function(string) {
    if (string.match(_escapeable)) {
      return '"' + string.replace(_escapeable, function (a)
      {
        var c = _meta[a];
        if (typeof c === 'string') { return c; }
        c = a.charCodeAt();
        return '\\u00' + Math.floor(c / 16).toString(16) +
          (c % 16).toString(16);
      }) + '"';
    }
    return '"' + string + '"';
  };

  var _escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;

  var _meta = {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '"' : '\\"',
    '\\': '\\\\'
  };

  $.toJSON = function(o) {
    if (typeof(JSON) == 'object' && JSON.stringify) {
      return JSON.stringify(o);
    }

    var type = typeof(o);

    if (o === null) {
      return "null";
    }

    if (type == "undefined") {
      return undefined;
    }

    if (type == "number" || type == "boolean") {
      return o + "";
    }

    if (type == "string") {
      return $.quoteString(o);
    }

    if (type == 'object') {
      if (typeof o.toJSON == "function") {
        return $.toJSON( o.toJSON() );
      }

      if (o.constructor === Date) {
        var month = o.getUTCMonth() + 1;
        if (month < 10) {
          month = '0' + month;
        }

        var day = o.getUTCDate();
        if (day < 10) {
          day = '0' + day;
        }

        var year = o.getUTCFullYear();

        var hours = o.getUTCHours();
        if (hours < 10) {
          hours = '0' + hours;
        }

        var minutes = o.getUTCMinutes();
        if (minutes < 10) {
          minutes = '0' + minutes;
        }

        var seconds = o.getUTCSeconds();
        if (seconds < 10) {
          seconds = '0' + seconds;
        }

        var milli = o.getUTCMilliseconds();
        if (milli < 100) {
          milli = '0' + milli;
        }
        if (milli < 10) {
          milli = '0' + milli;
        }

        return '"' + year + '-' + month + '-' + day + 'T' +
        hours + ':' + minutes + ':' + seconds +
        '.' + milli + 'Z"';
      }

      if (o.constructor === Array) {
        var ret = [];
        for (var i = 0; i < o.length; i++) {
          ret.push( $.toJSON(o[i]) || "null" );
        }

        return "[" + ret.join(",") + "]";
      }

      var pairs = [];
      for (var k in o) {
        var name;
        type = null;
        type = typeof k;
        if (type == "number") {
          name = '"' + k + '"';
        }
        else if (type == "string")  {
          name = $.quoteString(k);
        }
        else {
          continue;
        }
        if (typeof o[k] == "function") {
          continue;
        }
        var val = $.toJSON(o[k]);
        pairs.push(name + ":" + val);
      }
      return "{" + pairs.join(", ") + "}";
    }
  };
})(jQuery);
/*
 *
 * Copyright (c) 2006-2010 Sam Collett (http://www.texotela.co.uk)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version 1.1.1
 * Demo: http://www.texotela.co.uk/code/jquery/numeric/
 *
 */
(function($) {
/*
 * Allows only valid characters to be entered into input boxes.
 * Note: does not validate that the final text is a valid number
 * (that could be done by another script, or server-side)
 *
 * @name     numeric
 * @param    decimal      Decimal separator (e.g. '.' or ',' - default is '.')
 * @param    callback     A function that runs if the number is not valid (fires onblur)
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @example  $(".numeric").numeric();
 * @example  $(".numeric").numeric(",");
 * @example  $(".numeric").numeric(null, callback);
 *
 */
$.fn.numeric = function(decimal, callback)
{
	callback = typeof callback == "function" ? callback : function(){};
	this.keypress(
		function(e)
		{
			var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0;
			if(key == 13 && this.nodeName.toLowerCase() == "input")
			{
				return true;
			}
			else if(key == 13)
			{
				return false;
			}
			var allow = false;
			if((e.ctrlKey && key == 97 /* firefox */) || (e.ctrlKey && key == 65) /* opera */) return true;
			if((e.ctrlKey && key == 120 /* firefox */) || (e.ctrlKey && key == 88) /* opera */) return true;
			if((e.ctrlKey && key == 99 /* firefox */) || (e.ctrlKey && key == 67) /* opera */) return true;
			if((e.ctrlKey && key == 122 /* firefox */) || (e.ctrlKey && key == 90) /* opera */) return true;
			if((e.ctrlKey && key == 118 /* firefox */) || (e.ctrlKey && key == 86) /* opera */
			|| (e.shiftKey && key == 45)) return true;
			if(key < 48 || key > 57)
			{
				/* '-' only allowed at start */
				if(key == 45 && this.value.length == 0) return true;
				/* only one decimal separator allowed */
				if(typeof(decimal) !== 'undefined' && key == decimal.charCodeAt(0) && this.value.indexOf(decimal) != -1)
				{
					allow = false;
				}
				if(
					key != 8 /* backspace */ &&
					key != 9 /* tab */ &&
					key != 13 /* enter */ &&
					key != 35 /* end */ &&
					key != 36 /* home */ &&
					key != 37 /* left */ &&
					key != 39 /* right */ &&
					key != 46 /* del */
				)
				{
					allow = false;
				}
				else
				{
					if(typeof e.charCode != "undefined")
					{
						if(e.keyCode == e.which && e.which != 0)
						{
							allow = true;
						}
						else if(e.keyCode != 0 && e.charCode == 0 && e.which == 0)
						{
							allow = true;
						}
					}
				}
				if(typeof(decimal) !== 'undefined' && key == decimal.charCodeAt(0))
				{
					if(!this.containsDecimal)
					{
						allow = true;
						this.containsDecimal = true;
					}
					else
					{
						allow = false;
					}
				}
			}
			else
			{
				allow = true;
			}
			return allow;
		}
	)
	.blur(
		function()
		{
			var val = $(this).val();
			if(val != "")
			{
				var re = new RegExp("^\\d+$|\\d*" + decimal + "\\d+");
				if(!re.exec(val))
				{
					callback.apply(this);
				}
			}
		}
	);
	return this;
};

})(jQuery);
;(function($) {
  $.cookie = function(name, value, options) {
    if (typeof(value) != 'undefined') { // name and value given, set cookie
      options = options || {};
      if (value === null) {
        value = '';
        options.expires = -1;
      }
      var expires = '';
      if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
        var date;
        if (typeof options.expires == 'number') {
          date = new Date();
          date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
        } else {
          date = options.expires;
        }
        expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
      }
      var path = options.path ? '; path=' + (options.path) : '';
      var domain = options.domain ? '; domain=' + (options.domain) : '';
      var secure = options.secure ? '; secure' : '';
      document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    }
    else { // only name given, get cookie
      var cookieValue = null;
      if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
          var cookie = jQuery.trim(cookies[i]);
          if (cookie.substring(0, name.length + 1) == (name + '=')) {
            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
            break;
          }
        }
      }
      return cookieValue;
    }
  };
})(jQuery);
/**
 * @class Jaml
 * @author Ed Spencer (http://edspencer.net)
 * Jaml is a simple JavaScript library which makes HTML generation easy and pleasurable.
 * Examples: http://edspencer.github.com/jaml
 * Introduction: http://edspencer.net/2009/11/jaml-beautiful-html-generation-for-javascript.html
 */
Jaml = function() {
  return {
    templates: {},
    helpers  : {},

    /**
     * Registers a template by name
     * @param {String} name The name of the template
     * @param {Function} template The template function
     */
    register: function(name, template) {
      this.templates[name] = template;
    },

    /**
     * Renders the given template name with an optional data object
     * @param {String} name The name of the template to render
     * @param {Object} data Optional data object
     */
    render: function(name, data) {
      var template = this.templates[name],
          renderer = new Jaml.Template(template);

      return renderer.render(data);
    },

    /**
     * Registers a helper function
     * @param {String} name The name of the helper
     * @param {Function} helperFn The helper function
     */
    registerHelper: function(name, helperFn) {
      this.helpers[name] = helperFn;
    }
  };
}();
/**
 * @constructor
 * @param {String} tagName The tag name this node represents (e.g. 'p', 'div', etc)
 */
Jaml.Node = function(tagName) {
  /**
   * @property tagName
   * @type String
   * This node's current tag
   */
  this.tagName = tagName;

  /**
   * @property attributes
   * @type Object
   * Sets of attributes on this node (e.g. 'cls', 'id', etc)
   */
  this.attributes = {};

  /**
   * @property children
   * @type Array
   * Array of rendered child nodes that will be included as this node's innerHTML
   */
  this.children = [];
};

Jaml.Node.prototype = {
  /**
   * Adds attributes to this node
   * @param {Object} attrs Object containing key: value pairs of node attributes
   */
  setAttributes: function(attrs) {
    for (var key in attrs) {
      var mappedKey = key == 'cls' ? 'class' : key;

      this.attributes[mappedKey] = attrs[key];
    }
  },

  /**
   * Adds a child string to this node. This can be called as often as needed to add children to a node
   * @param {String} childText The text of the child node
   */
  addChild: function(childText) {
    this.children.push(childText);
  },

  /**
   * Renders this node with its attributes and children
   * @param {Number} lpad Amount of whitespace to add to the left of the string (defaults to 0)
   * @return {String} The rendered node
   */
  render: function(lpad) {
    lpad = lpad || 0;

    var node      = [],
        attrs     = [],
        textnode  = (this instanceof Jaml.TextNode),
        multiline = this.multiLineTag();

    for (var key in this.attributes) {
      attrs.push(key + '=' + this.attributes[key]);
    }

    if (!textnode) node.push(this.getPadding(lpad));

    node.push("<" + this.tagName);

    for (var key in this.attributes) {
      node.push(" " + key + "=\"" + this.attributes[key] + "\"");
    }

    if (this.isSelfClosing()) {
      node.push(" />\n");
    } else {
      node.push(">");

      if (multiline) node.push("\n");

      for (var i=0; i < this.children.length; i++) {
        node.push(this.children[i].render(lpad + 2));
      }

      if (multiline) node.push(this.getPadding(lpad));
      node.push("</", this.tagName, ">\n");
    }

    return node.join("");
  },

  /**
   * Returns true if this tag should be rendered with multiple newlines (e.g. if it contains child nodes)
   * @return {Boolean} True to render this tag as multi-line
   */
  multiLineTag: function() {
    var childLength = this.children.length,
        multiLine   = childLength > 0;

    if (childLength == 1 && this.children[0] instanceof Jaml.TextNode) multiLine = false;

    return multiLine;
  },

  /**
   * Returns a string with the given number of whitespace characters, suitable for padding
   * @param {Number} amount The number of whitespace characters to add
   * @return {String} A padding string
   */
  getPadding: function(amount) {
    return new Array(amount + 1).join(" ");
  },

  /**
   * Returns true if this tag should close itself (e.g. no </tag> element)
   * @return {Boolean} True if this tag should close itself
   */
  isSelfClosing: function() {
    var selfClosing = false;

    for (var i = this.selfClosingTags.length - 1; i >= 0; i--){
      if (this.tagName == this.selfClosingTags[i]) selfClosing = true;
    }

    return selfClosing;
  },

  /**
   * @property selfClosingTags
   * @type Array
   * An array of all tags that should be self closing
   */
  selfClosingTags: ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr',
                    'img', 'input', 'isindex', 'link', 'meta', 'param']
};

Jaml.TextNode = function(text) {
  this.text = text;
};

Jaml.TextNode.prototype = {
  render: function() {
    return this.text;
  }
};
/**
 * Represents a single registered template. Templates consist of an arbitrary number
 * of trees (e.g. there may be more than a single root node), and are not compiled.
 * When a template is rendered its node structure is computed with any provided template
 * data, culminating in one or more root nodes.  The root node(s) are then joined together
 * and returned as a single output string.
 *
 * The render process uses two dirty but necessary hacks.  First, the template function is
 * decompiled into a string (but is not modified), so that it can be eval'ed within the scope
 * of Jaml.Template.prototype. This allows the second hack, which is the use of the 'with' keyword.
 * This allows us to keep the pretty DSL-like syntax, though is not as efficient as it could be.
 */
Jaml.Template = function(tpl) {
  /**
   * @property tpl
   * @type Function
   * The function this template was created from
   */
  this.tpl = tpl;

  this.nodes = [];
};

Jaml.Template.prototype = {
  /**
   * Renders this template given the supplied data
   * @param {Object} data Optional data object
   * @return {String} The rendered HTML string
   */
  render: function(data) {
    data = data || {};

    if (data.constructor.toString().indexOf("Array") == -1) {
      data = [data];
    }

    with(this) {
      for (var i=0; i < data.length; i++) {
        eval("(" + this.tpl.toString() + ")(data[i])");
      };
    }

    var roots  = this.getRoots(),
        output = "";

    for (var i=0; i < roots.length; i++) {
      output += roots[i].render();
    };

    return output;
  },

  /**
   * Returns all top-level (root) nodes in this template tree.
   * Templates are tree structures, but there is no guarantee that there is a
   * single root node (e.g. a single DOM element that all other elements nest within)
   * @return {Array} The array of root nodes
   */
  getRoots: function() {
    var roots = [];

    for (var i=0; i < this.nodes.length; i++) {
      var node = this.nodes[i];

      if (node.parent == undefined) roots.push(node);
    };

    return roots;
  },

  tags: [
    "html", "head", "body", "script", "meta", "title", "link", "script",
    "div", "p", "span", "a", "img", "br", "hr",
    "table", "tr", "th", "td", "thead", "tbody",
    "ul", "ol", "li",
    "dl", "dt", "dd",
    "h1", "h2", "h3", "h4", "h5", "h6", "h7",
    "form", "input", "label", "select", "option", "optgroup",
    "strong", "iframe"
  ]
};

/**
 * Adds a function for each tag onto Template's prototype
 */
(function() {
  var tags = Jaml.Template.prototype.tags;

  for (var i = tags.length - 1; i >= 0; i--){
    var tagName = tags[i];

    /**
     * This function is created for each tag name and assigned to Template's
     * prototype below
     */
    var fn = function(tagName) {
      return function(attrs) {
        var node = new Jaml.Node(tagName);

        var firstArgIsAttributes =  (typeof attrs == 'object')
                                 && !(attrs instanceof Jaml.Node)
                                 && !(attrs instanceof Jaml.TextNode);

        if (firstArgIsAttributes) node.setAttributes(attrs);

        var startIndex = firstArgIsAttributes ? 1 : 0;

        for (var i=startIndex; i < arguments.length; i++) {
          var arg = arguments[i];

          if (arg instanceof Function) {
            arg = arg();
          }

          if (typeof arg == "string" || arg == undefined) {
            arg = new Jaml.TextNode(arg || "");
          }

          if (arg instanceof Jaml.Node || arg instanceof Jaml.TextNode) {
            arg.parent = node;
          }

          node.addChild(arg);

        };

        this.nodes.push(node);

        return node;
      };
    };

    Jaml.Template.prototype[tagName] = fn(tagName);
  };
})();

var Jaml;

Jaml.Template.prototype.h = function(x) {
  var arr = [[/&/g, "&amp;"],
             [/</g, "&lt;"],
             [/>/g, "&gt;"],
             [/"/g, "&quot;"]];
  $.each(arr, function(index, entry) {
    x = x.replace(entry[0], entry[1]);
  });
  return x;
};

Jaml.Template.prototype.textbox_with_label = function(id, txt, index, options) {
  var out = Jaml.render("label", {id: id, txt: txt});
  out += Jaml.render("textbox", {id: id, index: index, options: options});
  return out;
};

Jaml.Template.prototype.select_with_label =
  function(id, txt, index, options, select_options) {
    var out = Jaml.render("label", {id: id, txt: txt});
    out += Jaml.render("select",
      {id: id, index: index, options: options, sel_opt: select_options});
    return out;
};

Jaml.Template.prototype.checkbox_with_label =
  function(id, txt, index, options, value) {
    var out = Jaml.render("checkbox",
      {id: id, index: index, options: options, value: value});
    out += Jaml.render("label", {id: id, txt: txt});
    return out;
};

/* Vorlage zur Vereinfachung der option-Generierung in den Views
Jaml.Template.prototype.options = function(data, value_attr, name_attr) {
  if(typeof(value_attr) === 'undefined') {
    value_attr = 'value';
  }
  if(typeof(name_attr) === 'undefined') {
    name_attr = 'name';
  }
  var out = '';
  for(var i = 0; i < data.length; i++) {
    var entry = data[i];
    out += Jaml.render('option',
                       {value: entry[value_attr], name: entry[name_attr]});
  }
  return out;
};
*/
/*                    tinyTips Plugin                      */
/*                      Version: 1.1                       */
/*                      Mike Merritt                       */
/*                 Updated: Mar 2nd, 2010                  */

(function(a){a.fn.tinyTips=function(h,b){if(h==="null"){h="light"}var d=h+"Tip";var c='<div class="'+d+'"><div class="content"></div><div class="bottom">&nbsp;</div></div>';var e=300;var f;var g;a(this).hover(function(){a("body").append(c);var k="div."+d;f=a(k);f.hide();if(b==="title"){var i=a(this).attr("title")}else{if(b!=="title"){var i=b}}a(k+" .content").html(i);g=a(this).attr("title");a(this).attr("title","");var m=f.height()+2;var j=(f.width()/2)-(a(this).width()/2);var n=a(this).offset();var l=n;l.top=n.top-m;l.left=n.left-j;f.css("position","absolute").css("z-index","1000");f.css(l).fadeIn(e)},function(){a(this).attr("title",g);f.fadeOut(e,function(){a(this).remove()})})}})(jQuery);

var SearchMask = {};

SearchMask.unload = function() {
  return true;
}

SearchMask.init = function(affiliate, start_params) {

  var standard_affiliate = {agent: "NixWieWegde", subagent1: "", subagent2: ""};
  SearchMask.start_params = $.extend({engine: "lastminute"}, start_params);
  SearchMask.affiliate = $.extend(standard_affiliate, affiliate);

  if (SearchMask.start_params.engine == "earth") {
    SearchMask.EarthController.index();
  }
  else {
    SearchMask.LastminuteController.index();
  }

  $.fix_ie_disabled_options();

  if (SearchMask.start_params.full) {
    $("#more").click();
    $("#less").hide();
  }
};

var SM = SearchMask;
SearchMask.Settings = {
  tt_booking_url: 'http://reisen.nix-wie-weg.de/booking/nixwieweg/index.php',
  tt_booking_earth_url:
    'http://reisen.nix-wie-weg.de/booking/nixwieweg/erde/index.php',
  tt_kid: 699000,
  cookie_domain: (env == "production") ? ".nix-wie-weg.de" : ""
};
SearchMask.Cookie = new JS.Class({

  initialize: function(type) {
    this.cookie_name = "TT_SEARCH";
    this.type = type;
  },
  fresh_node: function() {
    var items = "abflughafen alter1 alter2 alter3 dauer erwachsene kategorie ";
    items += "kmonat ktag rueckkmonat rueckktag ziel";
    var node = {};
    $.each(items.split(" "), function (i,item){
      node[item] = "";
    });
    $.each("alter1 alter2 alter3".split(" "), function(i, o) {
      node[o] = "-1";
    });
    return node;
  },
  fresh_cookie: function() {
    var self = this;
    var cookie = {};
    $.each("F FH H LM P".split(" "), function(i,key) {
      cookie[key] = self.fresh_node();
    });
    return cookie;
  },
  get: function() {
    var x = null;
    try {
      x = $.parseJSON($.cookie(this.cookie_name));
    } catch(e) {}
    return x;
  },
  put: function(form_state) {
    var cook = this.get();
    if (cook === null) {cook = this.fresh_cookie();}
    cook[this.type] = this.build_hash_from_form_state(form_state);
    $.cookie(this.cookie_name, $.toJSON(cook),
      {expires: 60, path: "/", domain: SearchMask.Settings.cookie_domain});
  },

  build_hash_from_form_state: function(form_state) {
    var hash = this.fresh_node();
    try {
      hash.dauer = form_state.duration.duration_id + "";

      if($.is_defined(form_state, 'departure_airport')) {
        var airports = [];
        if (form_state.departure_airport.entries.length == 1) {
          airports.push(form_state.departure_airport.entries[0].value);
        } else {
          $.each(form_state.departure_airport.entries, function(i, o){
            airports.push(o.dlc);
          });
        }
        hash.abflughafen = (airports.length === 0) ? "-1" : airports.join(",") +
                           "";
      }

      hash.kategorie = form_state.category.value + "";
      hash.ziel = form_state.destination.entry.value + "";

      var people = [];
      for (var i=0;i<form_state.travelers.adult_count;i++) {
        people.push(25);
      }
      hash.erwachsene = people.join(";");
      $.each(form_state.travelers.children_with_age, function(i, o) {
        hash["alter"+(i+1)] = o + "";
      });
      var out_date = form_state.date_range.outgoing_date;
      hash.ktag = out_date.getDate() + "";
      hash.kmonat = out_date.getMonth() + 1 + "." + out_date.getFullYear();
      var ret_date = form_state.date_range.return_date;
      hash.rueckktag = ret_date.getDate() + "";
      hash.rueckkmonat = ret_date.getMonth() + 1 + "." + ret_date.getFullYear();
    } catch(e) {
    }
    return hash;
  },
  to_hash: function(part) {
    if (typeof(part) === "undefined") { part = this.type; }
    var cookie = this.get();
    if (cookie === null) { return({}); }
    var cp = {};
    if ($.is_defined(cookie, part)) {
      cp = cookie[part];
      if ($.is_defined(cp, "ziel")) {
        cp.zielgebiets_kenner = cp.ziel;
        delete cp.ziel;
      }
      cp.personen = [];
      if ($.is_defined(cp, "erwachsene")) {
        cp.personen = $.find_all(cp.erwachsene.split(";"), function(o) {
          return o.length > 0;
        });
        delete cp.erwachsene;
      }
      if ($.is_defined(cp, "abflughafen")) {
        var z =
          $.find_all(cp.abflughafen.split(","), function(o) {
          return o.length > 0;
        });
        cp.abflughafen = z.join(",");
      }
      $.each([1, 2, 3], function(i, z) {
        if ($.is_defined(cp, "alter"+z) && (cp["alter" +z] !== "")) {
          cp.personen.push(cp["alter"+z]);
          delete cp["alter"+z];
        }
      });
      cp.personen = cp.personen.join(";");
      if ($.is_defined(cp, "ktag") && $.is_defined(cp, "kmonat")) {
        cp.termin = cp.ktag + "." + cp.kmonat;
        delete cp.ktag;
        delete cp.kmonat;
      }
      if ($.is_defined(cp, "rueckktag") && $.is_defined(cp, "rueckkmonat")) {
        cp.ruecktermin = cp.rueckktag + "." + cp.rueckkmonat;
        delete cp.rueckktag;
        delete cp.rueckkmonat;
      }
    }
    return cp;
  }
});
SearchMask.DateMap = new JS.Singleton({
  initialize: function() {
    this.date_map = {};
    this.selected = "all";
    this.dates = [];
    this.selected_date = null;
  },
  add_date: function(date) {
    if (this.dates.length == 2) {
      this.dates = [];
    }
    date.setHours(0);
    this.dates.push(date);
    this.dates = this.dates.sort(function(a,b) {
      return a.valueOf() - b.valueOf();
    });
  },
  start_date: function() {
    var z = this.dates[0];
    return (z === undefined) ? null : z;
  },
  start_date_str: function() {
    return this.date_to_string(this.start_date());
  },
  end_date: function() {
    var z = this.dates[1];
    return (z === undefined) ? null : z;
  },
  end_date_str: function() {
    return this.date_to_string(this.end_date());
  },
  date_to_string: function(date) {
    if (date === null) {return "";}
    return [date.getDate(), date.getMonth() + 1, date.getFullYear()].join('.');
  },
  find_by_state: function(state) {
    var official_holidays, school_holidays  = [];
    var map = {};
    if (state && (state !== "all"))  {
      official_holidays = SearchMask.OfficialHoliday.find_by_state(state);
      school_holidays = SearchMask.SchoolHoliday.find_by_state(state);
    } else {
      official_holidays = SearchMask.OfficialHoliday.find_uniform();
    }
    $.each(school_holidays, function(i, holiday) {
      if (holiday.state_datums[state] === null) {
        return;
      }
      $.each(holiday.state_datums[state], function(i, date) {
        var begin = date.from.getTime();
        var end = date.to.getTime();
        for (var y = begin; y <= end; y = y + (86400 * 1000)) {
          map[y] = holiday;
        }
      });
    });
    $.each(official_holidays, function(i, holiday) {
      $.each(holiday.datums, function(i, date) {
        map[date.valueOf()] = holiday;
      });
    });
    this.date_map = map;
  },
  is_holiday: function(date_value) {
    if ($.is_defined(this.date_map, date_value)) {
      return this.date_map[date_value];
    }
    else {
      return false;
    }
  }
});
SearchMask.Infobox = new JS.Class({
  initialize: function(div_id) {
    if(typeof(div_id) === "undefined") {div_id = "infobox";}
    this.div_id = div_id;
  },
  show: function(content) {
    var content_div = "#" + this.div_id + " .content";
    var pos_box = "#" + this.div_id + "_pos";
    $(content_div).html(content);
    $(pos_box).show();
  },
  render: function(content) {
    var content_div = "#" + this.div_id + " .content";
    $(content_div).replaceWith(content);
  },
  render_template: function(template_name) {
    var popup = Jaml.render(template_name);
    this.render(popup);
  },
  show_template: function(template_name) {
    var popup = Jaml.render(template_name);
    this.show(popup);
  }
});
SearchMask.ParamLogic = new JS.Class({
  url_to_hash: function(params_url) {
    var hash = {};
    var hashes = params_url.slice(params_url.indexOf('?') + 1).split("&");
    for(var i = 0; i < hashes.length; i++) {
      var temp = hashes[i].split('=');
      if (temp.length < 2) {
        temp[1] = "";
      }
      hash[temp[0]] = decodeURIComponent(temp[1]);
    }
    return hash;
  },
  preference_zfilter: function(param) {
    zfilter = this.number_to_bitset(param);
    if (zfilter[21]) {this.preferences.seaview = true;}
    if (zfilter[25]) {this.preferences.children_discount = true;}
    if (zfilter[26]) {this.preferences.early_booking = true;}

    var acc_extended = -1;
    for (var i = 16; i > 0; i = i-1) {
      if (zfilter[i]) {
        acc_extended = Math.pow(2,i-1);
        break;
      }
    }
    if (acc_extended > -1) {
      this.preferences.accomodation_extended = acc_extended;
      this.preferences.accomodation = -2;
    }
  },
  number_to_bitset: function(number) {
    var bitset = ((number).toString(2)+"0").split("").reverse();
    var bits = $.map(bitset, function(bit) {
      return (parseInt(bit, 10) === 1);
    });
    return bits;
  },
  preference_if: function(preference, value, filters) {
    if (typeof(value) === "undefined") { return; }
    $.each(filters, function(i, filter) {
      if (value === null) { return; }
      else if (filter == "int") {
        value = (isNaN(parseInt(value, 10))) ? false : parseInt(value, 10) ;
      }
      else if (filter == "bool") {
        value = (value < 0) ? false : true;
      }
      else if (filter == "array_int_;") {
        value = $.map(value.split(";"), function(v) {
          return (isNaN(parseInt(v, 10))) ? null : parseInt(v, 10);
        });
      }
      else if (filter == "array_int__") {
        value = $.map(value.split("_"), function(v) {
          return (isNaN(parseInt(v, 10))) ? null : parseInt(v, 10);
        });
      }
      else if (filter == "array_string_,") {
        value = $.map(value.split(","), function(v) {
          v = (isNaN(parseInt(v, 10))) ? v : parseInt(v, 10);
          return v;
        });
      }
      else if (filter == "array_string_;") {
        value = $.map(value.split(";"), function(v) {
          v = (isNaN(parseInt(v, 10))) ? v : parseInt(v, 10);
          return v;
        });
      }
      else if (filter == "string") {
        value = (value.length > 0) ? value : null;
      }
    });
    if (value || (value === 0)) { this.preferences[preference] = value; }
  }
});

SearchMask.ParamsConverter = new JS.Class(SearchMask.ParamLogic, {
  initialize: function() {
    this.preferences = {};
  },
  to_hash: function() {
    return this.preferences;
  },
  from_hash: function(hash) {
    if (typeof(hash) === "undefined") {hash = {}; }
    this.modify_by_url_params(hash);
    return this;
  },
  from_url: function(url) {
    if (typeof(url) === "undefined") {url = location.search;}
    var url_hash = this.url_to_hash(url);
    this.modify_by_url_params(url_hash);
    return this;
  },
  modify_by_url_params: function(params) {
    this.preference_if("accomodation", params.zimmer, ["int"]);
    this.preference_if("beach",
                       params.strand, ["int","bool"]);
    this.preference_if("category_id", params.kategorie, ["int"]);
    this.preference_if("catering_id", params.verpflegung, ["int"]);
    this.preference_if("family_children",
                       params.familie_kinder, ["int","bool"]);
    this.preference_if("club",
                       params.typ, ["int","bool"]);
    this.preference_if("destination_id", params.zielgebiets_kenner,["int"]);
    this.preference_if("departure_airport_id",
                       params.abflughafen,["array_string_,"]);
    this.preference_if("duration_id", params.dauer, ["string"]);
    this.preference_if("hotel_name", params.shotel, ["string"]);
    this.preference_if("engine", params.dauer, ["string"]);
    this.preference_if("travelers", params.personen, ["array_int_;"]);
    if (this.preferences.travelers) {
      this.preferences.travelers =
        $.find_all(this.preferences.travelers, function(o) { return o > 0; });
    }
    this.preference_if("price", params.preis, ["int"]);
    this.preference_if("operator_id", params.marke, ["string"]);
    this.preference_if("outgoing_date", params.termin, ["string"]);
    this.preference_if("return_date", params.ruecktermin, ["string"]);
    this.preference_if("seaview", params.meer, ["int","bool"]);
    this.preference_if("sport_id", params.sportangebot, ["int"]);
    this.preference_if("theme_id", params.uthema, ["array_int__"]);
    this.preference_if("wellness", params.wellness, ["int","bool"]);
    this.preference_if("zfilter", params.zfilter, ["int"]);
    if (typeof(this.preferences.zfilter) !== "undefined") {
      this.preference_zfilter(this.preferences.zfilter);
    }
  }
});


String.prototype.score = function(abbreviation,offset) {
  offset = offset || 0

  if(abbreviation.length == 0) return 0.9
  if(abbreviation.length > this.length) return 0.0

  for (var i = abbreviation.length; i > 0; i--) {
    var sub_abbreviation = abbreviation.substring(0,i)
    var index = this.indexOf(sub_abbreviation)


    if(index < 0) continue;
    if(index + abbreviation.length > this.length + offset) continue;

    var next_string       = this.substring(index+sub_abbreviation.length)
    var next_abbreviation = null

    if(i >= abbreviation.length)
      next_abbreviation = ''
    else
      next_abbreviation = abbreviation.substring(i)

    var remaining_score   = next_string.score(next_abbreviation,offset+index)

    if (remaining_score > 0) {
      var score = this.length-next_string.length;

      if(index != 0) {
        var j = 0;

        var c = this.charCodeAt(index-1)
        if(c==32 || c == 9) {
          for(var j=(index-2); j >= 0; j--) {
            c = this.charCodeAt(j)
            score -= ((c == 32 || c == 9) ? 1 : 0.15)
          }

        } else {
          score -= index
        }
      }

      score += remaining_score * next_string.length
      score /= this.length;
      return score
    }
  }
  return 0.0
}
/* Basiert auf dem "Select Autocompleter" von Kyle Neath
 * http://warpspire.com/tipsresources/interface-scripting/select-autocompleter/
 * Hauptänderungen: Portierung von MooTools auf jQuery
 *
 * Code durchaus noch überarbeitbar
 *
 * Das Scrollverhalten könnte z.B. mit .scrollTop, .scrollHeight und .offsetTop
 * beeinflusst werden.
 */
var SelectAutocompleter = new JS.Class({
  defaults: {
    cutoff_score: 0.1
  },
  initialize: function(input_selector, countries, options) {
    var self = this;

    this.data = [];
    this.data_by_value = [];
    this.terms = [];
    this.filtered_terms = [];
    this.set_options(options);
    this.value = null;
    this.default_entry = countries[0];

    this.element = $(input_selector);
    this.element.focus(function(event) {
      self.on_focus_element();
    });
    this.element.keydown(function(event) {
      self.on_keydown_element(event);
    });
    this.element.keyup(function(event) {
      self.on_keyup_element(event);
    });
    $(document).mousedown(function(event) {
      setTimeout(function() { self.after_mouse_down(event); }, 300);
    });

    this.drop_down = $('<ul></ul>').addClass('auto-dropdown');
    this.drop_down.hide();
    $("#dest_dropdown").children().remove();
    $('#dest_dropdown').append(this.drop_down);

    if($.browser.msie && parseInt($.browser.version, 10) < 7) {
      var iframe =
        '<iframe style="filter:alpha(opacity=0);" src="javascript:false;" ' +
        'frameborder="0" scrolling="no"></iframe>';
      this.iframe = $(iframe);
      this.iframe.hide();
      $('#dest_dropdown').append(this.iframe);
    }

    $.each(countries, function(idx, country) {

      self.data[country.name] = country;
      self.data_by_value[country.value] = country;
      self.terms.push(country.name);

      $.each(country.regions, function(idx2, region) {

        self.data[region.name] = region;
        self.data_by_value[region.value] = region;
        self.terms.push(region.name);
      });
    });
  },

  set_options: function(new_options) {
    this.options = $.extend({}, this.defaults, this.options, new_options);
  },

  update_terms_list: function() {

    var self = this;
    var filter_value = this.element.val();

    this.build_filtered_terms(filter_value);

    this.drop_down.empty();

    var letters = [];
    for(var i = 0; i < filter_value.length; i++) {
      var letter = filter_value.substr(i, 1);
      if($.inArray(letter, letters) == -1) {
        letters.push(letter);
      }
    }

    $.each(this.filtered_terms, function(index, scored_term) {

      var formatted_string = scored_term[1];
      if(filter_value.length > 0) {
        var regexp = new RegExp("([" + letters.join('') + "])", "ig");
        formatted_string = formatted_string.replace(regexp,
                                                    "<strong>$1</strong>");
      }

      var item_data = self.data[scored_term[1]];
      var inner = "";

      if(item_data.type == 'country') {
        inner = formatted_string;
      } else if(item_data.type == 'region') {
        inner = formatted_string + " (" + item_data.country_name() + ")";
      }

      var choice = $('<li>' + inner + '</li>');
      choice.addClass(item_data.type);
      choice.attr('raw_text', scored_term[1]);
      choice.click(function() {
        self.term_chosen = scored_term[1];
      });
      choice.mouseover(function() {
        self.highlight(choice);
      });
      self.drop_down.append(choice);
    });
  },

  highlight: function(elem) {
    if(this.highlighted_choice) {
      $(this.highlighted_choice).removeClass('highlighted');
    }
    $(elem).addClass('highlighted');
    this.highlighted_choice = elem;
  },

  build_filtered_terms: function(filter) {
    var self = this;

    this.filtered_terms = [];

    $.each(this.terms, function(idx, term) {
      var score = term.toLowerCase().score(filter.toLowerCase());
      if (score < self.options.cutoff_score) {
        return;
      }
      self.filtered_terms.push([score, term]);
    });

    if(filter.length > 0) {
      this.filtered_terms.sort(function(a, b) {return b[0] - a[0];});
    }

    if(this.filtered_terms.length > 0) {
      this.unset_empty_indicator();
    } else {
      this.set_empty_indicator();
    }
  },

  after_mouse_down: function(event) {



    var close = !($(event.target).hasClass('auto-dropdown') ||
                  event.target.id == 'destination_id');


    if(close && this.drop_down.is(':visible')) {
      this.on_blur_element();
    }
  },

  on_focus_element: function() {
    this.element.val('');
    this.term_chosen = null;

    this.show_drop_down();
    this.update_terms_list();
  },

  on_blur_element: function() {
    this.hide_drop_down();
    this.highlighted_choice = null;

    if(this.term_chosen !== null) {
      this.element.val(this.term_chosen);
      this.value = this.data[this.term_chosen].value;
    } else {
      this.unset();
    }
  },

  on_keydown_element: function(event) {
    if(event.which == 9) {  // Tab
      this.on_enter_or_tab(event);
    }
  },

  on_keyup_element: function(event) {

    if (event.which == 27) { // Escape
      this.on_blur_element();
      this.element.blur();

    } else if(event.which == 38 || event.which == 40) { // Up, Down

      var choices = $(this.drop_down).children('li');
      if (choices.length === 0) {
        return;
      }
      var idx = $.inArray(this.highlighted_choice, choices);

      if (this.highlighted_choice === null || idx == -1) {
        this.highlight(choices[0]);
        return;
      }

      switch(event.which) {
        case 38: // up
          if (idx === 0) {
            this.highlight(choices[0]);
          } else {
            this.highlight(choices[idx - 1]);
          }
        break;
        case 40: // down
          if(idx == choices.length - 1) {
            this.highlight(choices[choices.length - 1]);
          } else {
            this.highlight(choices[idx + 1]);
          }
        break;
      }
    } else if (event.which == 13) { // return
      event.stopPropagation(); // to prevent the form from being submitted
      this.on_enter_or_tab(event);
      $('#operator_id')[0].focus();
    } else {
      this.update_terms_list();
    }
  },

  on_enter_or_tab: function(event) {
    if(this.highlighted_choice === null ||
       typeof(this.highlighted_choice) === 'undefined') {
      if(this.filtered_terms.length > 0) {
        this.term_chosen = this.filtered_terms[0][1];
      }
    } else {
      this.term_chosen = $(this.highlighted_choice).attr('raw_text');
    }
    this.highlighted_choice = null;
    this.on_blur_element();
  },

  set_value: function(value) {
    var entry = this.data_by_value[value];
    this.element.val(entry.name);
    this.value = entry.value;
  },

  set_by_form_state: function(form_state) {
    var id = form_state.destination.entry.value;
    if (this.data_by_value[id]) {
      this.set_value(id);
    }
  },

  unset: function() {
    this.element.val(this.default_entry.name);
    this.value = this.default_entry.value;
    this.unset_empty_indicator();
    this.highlighted_choice = null;
  },
  set_empty_indicator: function() {
    this.element.addClass('empty');
  },
  unset_empty_indicator: function() {
    this.element.removeClass('empty');
  },

  show_drop_down: function() {
    if(this.iframe) {
      this.iframe.show();
    }
    this.drop_down.show();
  },

  hide_drop_down: function() {
    if(this.iframe) {
      this.iframe.hide();
    }
    this.drop_down.hide();
  }
});
SearchMask.FinderLogic = new JS.Class({
  put_to_form: function(form) {
    return $(this.klass.element_selector, form).val(this.get_value());
  },
  extend: {
    find_all: function() {
      if(typeof(this.all_objects) === 'undefined') {
        this.all_objects = this.fetch_all();
      }
      return this.all_objects;
    },
    find_lastminute: function(){
      return $.find_all(this.find_all(), function(o){ return o.lastminute; });
    },
    find_earth: function(){
      return $.find_all(this.find_all(), function(o){ return o.earth; });
    },
    default_entry: function() {
      return this.find_all()[0];
    },
    find_by_id: function(id) {
      return $.detect(this.find_all(), function(obj) {
        return obj.get_value() == id;
      });
    },
    find_by: function(key, value) {
      return $.detect(this.find_all(), function(obj) {
        return obj[key] == value;
      });
    },
    find_by_form: function(form) {
      return this.find_by_id($(this.element_selector, form).val());
    },
    from_url_params: function(params) {
      var object = null;
      var params_id = this.url_param_id();
      if (typeof(params[params_id]) !== "undefined") {
        object = this.find_by_url_param(params[params_id]);
      }
      if (!object) { object = this.default_entry(); }
      return object;
    },
    find_by_url_param: function(param) {
      return this.find_by_id(param);
    },
    url_param_id: function() {
      return this.underscore_class_name + "_id";
    }
  }
});

SearchMask.SimpleNameValuePair = new JS.Class(SearchMask.FinderLogic, {
  initialize: function(name, value) {
    this.name = name;
    this.value = value;
  },
  to_url_params: function() {
    if(this.klass.default_entry().value == this.value) {
      return {};
    }
    var ret = {};
    ret[this.klass.tt_key] = this.value;
    return ret;
  },
  get_value: function(){
    return this.value;
  }
});

SearchMask.AccomodationType = new JS.Class(SearchMask.FinderLogic, {
  initialize: function(name, value, additional) {
    if(additional === undefined) {
      additional = false;
    }
    this.name = name;
    this.value = value;
    this.additional = additional;
  },
  put_to_form: function(form) {
    $(this.klass.element_selector, form).val(this.form_value());
  },
  form_value: function() {
    if(this.additional) {
      return 'ate_' + this.value;
    } else {
      return 'at_' + this.value;
    }
  },
  is_default_entry: function() {
    var def = this.klass.default_entry();
    return this.additional == def.additional && this.value == def.value;
  },
  to_url_params: function() {
    if(this.is_default_entry()) {
      return {};
    }

    var ret = {};
    if(this.additional) {
      ret.zimmer = -2;
      ret.zfilter = this.value;
    } else {
      ret.zimmer = this.value;
    }
    return ret;
  },
  get_value: function(){
      return this.value;
  },
  extend: {
    fetch_all: function() {
      return [
        new this('beliebig', -1),
        new this('Einzelzimmer', 5),
        new this('Doppelzimmer', 6),
        new this('Familienzimmer', 2),
        new this('Bungalow', 0),
        new this('Apartment', 7),
        new this('Studio', 2, true),
        new this('Suite', 16, true),
        new this('Villa', 256, true),
        new this('Superior', 512, true),
        new this('Dreibettzimmer', 1024, true),
        new this('Mehrbettzimmer', 4096, true),
        new this('Ferienwohnung', 8192, true),
        new this('Ferienhaus', 16384, true),
        new this('Deluxe-Zimmer', 32768, true),
        new this('Duplexzimmer', 2048, true)
      ];
    },
    from_url_params: function(params) {
      var obj = null;
      if($.is_defined(params, "accomodation")) {
        var p;
        if (params.accomodation == -2) {
          p = params.accomodation_extended;
          obj =this.find_by_value_and_additional(p, true);
        }
        else {
          p = params.accomodation;
          obj = this.find_by_value_and_additional(p, false);
        }
      }
      return ((obj) ? obj :this.default_entry());
    },
    element_selector: '#accomodation_type_id',
    underscore_class_name: 'accomodation_type',
    find_by_form: function(form) {
      var x = $(this.element_selector, form).val();
      var pair = x.split('_');
      var additional = false;
      if(pair[0] == 'ate') {
        additional = true;
      }
      var found = this.find_by_value_and_additional(pair[1], additional);
      return found;
    },
    find_by_value_and_additional: function(value, additional) {
      if(additional === undefined) {
        additional = false;
      }
      return $.detect(this.find_all(), function(obj) {
        return obj.value == value && obj.additional == additional;
      });
    }
  }
});
SearchMask.Affectations = new JS.Class(SearchMask.SimpleNameValuePair, {
  put_to_form: function(form) {
    $(this.klass.element_selector, form).attr("checked", this.name);
  },
  extend: {
    fetch_all: function() {
      return [
        new this(false, -1),
        new this(true, this.used_value)
      ];
    },
    find_by_form: function(form) {
      var val = $(this.element_selector,form).is(":checked");
      return this.find_by_id((val) ? this.used_value: -1);
    },
    find_by_name: function(name) {
      return this.find_by('name', name);
    },
    find_by_url_param: function(param) {
      return this.find_by_name(param);
    },
    url_param_id: function() {
      return this.underscore_class_name;
    },
    used_value: 0
  }
});

SearchMask.FamilyChildren = new JS.Class(SearchMask.Affectations, {
  extend: {
    element_selector: '#family_children',
    underscore_class_name: 'family_children',
    tt_key: 'familie_kinder'
  }
});

SearchMask.Beach = new JS.Class(SearchMask.Affectations, {
  extend: {
    element_selector: '#beach',
    underscore_class_name: 'beach',
    tt_key: 'strand'
  }
});

SearchMask.Wellness = new JS.Class(SearchMask.Affectations, {
  extend: {
    element_selector: '#wellness',
    underscore_class_name: 'wellness',
    tt_key: 'wellness'
  }
});

SearchMask.Seaview = new JS.Class(SearchMask.Affectations, {
  extend: {
    used_value: 1048576,
    element_selector: '#seaview',
    underscore_class_name: 'seaview',
    tt_key: 'meer'
  }
});

SearchMask.Club = new JS.Class(SearchMask.Affectations, {
  extend: {
    element_selector: '#club',
    underscore_class_name: 'club',
    tt_key: 'typ'
  }
});

SearchMask.Category = new JS.Class(SearchMask.SimpleNameValuePair, {
  put_to_form: function(form) {
    var selector = "#category_id input[name='category_id']";
    selector += "[value=" + this.value + "]";
    $(selector, form).attr('checked', 'checked');
  },
  stars: function(){
    var cnt = 0;
    if(this.value != -1){
      cnt = this.value+2;
    }
    return cnt;
  },
  extend: {
    fetch_all: function() {
      return [
        new this('egal', -1),
        new this('2 Sterne', 0),
        new this('3 Sterne', 1),
        new this('4 Sterne', 2),
        new this('5 Sterne', 3)
      ];
    },
    element_selector: "#category_id input[name='category_id']:checked",
    underscore_class_name: 'category',
    tt_key: 'kategorie'
  }
});

SearchMask.Catering = new JS.Class(SearchMask.SimpleNameValuePair, {
  extend: {
    fetch_all: function() {
      return [
        new this('beliebig', -1),
        new this('nur Übernachtung', 0),
        new this('Frühstück', 1),
        new this('Halbpension', 2),
        new this('Vollpension', 3),
        new this('All Inclusive', 4)
      ];
    },
    element_selector: '#catering_id',
    underscore_class_name: 'catering',
    tt_key: 'verpflegung'
  }
});
SearchMask.DateRange = new JS.Class({
  initialize: function(outgoing_date, return_date) {
    this.outgoing_date = outgoing_date;
    this.return_date = return_date;
  },
  put_to_form: function(form) {
    $('#outgoing', form).val(this.outgoing_date_string());
    $('#return', form).val(this.return_date_string());
    var diff = ((this.return_date - this.outgoing_date) / (1000 * 60*60*24));
    if (diff < 60) {
      $.each([this.outgoing_date, this.return_date], function(i, ele) {
        SearchMask.DateMap.add_date(ele);
      });
      SearchMask.DateMap.selected_date = this.outgoing_date;
    }
  },
  outgoing_date_string: function() {
    return this.klass.date_to_german_date_string(this.outgoing_date);
  },
  return_date_string: function() {
    return this.klass.date_to_german_date_string(this.return_date);
  },
  to_url_params: function() {
    return {
      termin: this.outgoing_date_string(),
      ruecktermin: this.return_date_string()
    };
  },
  validate: function(form_state) {
    var nights = (this.return_date - this.outgoing_date) / (1000*60*60*24);

    form_state.duration.limit(nights, form_state.form_element);
  },
  extend: {
    from_url_params: function(params) {
      var default_date = this.default_entry();
      var def_out_date = default_date.outgoing_date;
      var def_ret_date = default_date.return_date;
      var out_date = this.date_from_url(params.outgoing_date);
      var ret_date = this.date_from_url(params.return_date);
      if (out_date === null && ret_date === null) {
        return this.default_entry();
      }
      if ((out_date === null) || (out_date < def_out_date) ||
          (out_date > def_ret_date)) {
        out_date = def_out_date;
      }
      if ((ret_date === null) || (ret_date > def_ret_date) ||
          (ret_date < def_out_date)) {
        ret_date = def_ret_date;
      }
      out_date.setHours(12);
      return new this(out_date, ret_date);
    },
    date_from_url: function(param) {
      var date;
      if (typeof(param) === "undefined") {
        return null;
      }
      if (param == "-1.-1") {
        return null;
      }
      else if (parseInt(param, 10) < 32) {
        date = this.german_date_string_to_date(param);
      }
      else if (parseInt(param, 10) > 32){
        date = new Date(parseInt(param, 10)*1000);
      }
      else {
        date = null;
      }
      return date;
    },
    find_by_form: function(form) {
      var o = $('#outgoing', form).val();
      var r = $('#return', form).val();

      var outgoing = this.german_date_string_to_date(o);
      outgoing.setHours(12);
      return new this(outgoing, this.german_date_string_to_date(r));
    },
    default_entry: function() {


      var now = new Date().getTime();
      var one_day = 86400 * 1000;

      var in_three_days = new Date(now + 3 * one_day);
      in_three_days.setHours(12);
      in_three_days.setMinutes(0);
      in_three_days.setSeconds(0);
      in_three_days.setMilliseconds(0);

      var in_376_days = new Date(now + 376 * one_day);
      in_376_days.setHours(0);
      in_376_days.setMinutes(0);
      in_376_days.setSeconds(0);
      in_376_days.setMilliseconds(0);

      return new this(in_three_days, in_376_days);
    },
    calendar_default_entry: function() {
      var entries = this.default_entry();
      entries.outgoing_date = new Date();
      return entries;
    },
    underscore_class_name: 'date_range',
    german_date_string_to_date: function(str) {
      var arr = str.split('.');
      var d = new Date();
      d.setMonth(arr[1] - 1, arr[0]);
      d.setYear(arr[2]);
      return d;
    },
    date_to_german_date_string: function(date) {
      var arr = [date.getDate(), date.getMonth() + 1, date.getFullYear()];
      return arr.join('.');
    }
  }
});

SearchMask.DepartureAirport = new JS.Class({
  initialize: function(entries) {
    this.entries = entries;
  },
  put_to_form: function(form) {
    var ele_ids = $.map(this.entries, function(x) { return x.element_id(); });
    $('#airportbox input[type="checkbox"]', form).each(function(idx, input) {
      input.checked = $.inArray(input.id, ele_ids) >= 0;
    });
  },
  to_url_params: function() {
    var str = null;
    var ret = {};
    if(this.entries[0].klass == this.klass.DefaultEntry) {
    } else if(this.entries.length == 1) {
      str = this.entries[0].value;
    } else {
      var dlcs = $.map(this.entries.slice(0, 3), function(e) {return e.dlc;});
      str = dlcs.join(',');
    }

    if(str) {
      ret[this.klass.tt_key] = str;
    }
    return ret;
  },
  to_string: function() {
    return $.map(this.entries, function(x) {return x.name;}).join(', ');
  },
  extend: {
    find_default_entry: function() {
      return new this.DefaultEntry();
    },
    find_all_real_entries: function() {
      if(typeof(this.real_entries) === 'undefined') {
        this.real_entries = this.RealEntry.fetch_entries();
      }
      return this.real_entries;
    },
    find_all_virtual_entries: function() {
      if(typeof(this.virtual_entries) === 'undefined') {
        this.virtual_entries = this.VirtualEntry.fetch_entries();
      }
      return this.virtual_entries;
    },

    from_url_params: function(params) {
      var self = this;
      var arr = params.departure_airport_id;
      var objects = [];
      if(typeof(arr) !== 'undefined') {
        objects = $.map(arr, function(idx, input) {
          if(idx === 'undefined') {
            return self.find_default_entry();
          } else if(typeof(idx) !== 'number') {
            return self.find_entry_by_element_dlc(idx);
          } else {
            return self.find_entry_by_element_id("airport_"+idx);
          }
        });
        objects = this.classify_array(objects, self);
      } else {

        objects = [this.find_default_entry()];
      }
      return new this(objects);
    },
    find_by_form: function(form) {
      var self = this;
      var objects = $('#airportbox input:checked', form)
                      .map(function(idx, input) {
        return self.find_entry_by_element_id(input.id);
      });
      objects = this.classify_array(objects, self);
      return new this(objects);
    },
    classify_array: function(objects, self){
      var x = $.detect(objects, function(a) {
        return a.klass == self.DefaultEntry;
      });
      if(x) {
        objects = [x];
      } else {
        x = $.detect(objects, function(a) {
          return a.klass == self.VirtualEntry;
        });
        if(x) {
          objects = [x];
        }
      }

      if(objects.length > 3) {
        objects.length = 3;
      }

      return objects;
    },
    find_entry_by_element_id: function(element_id) {
      var id = element_id.split('_')[1];
      if(id == this.find_default_entry().value) {
        return this.find_default_entry();
      } else {
        var virtual = $.detect(this.find_all_virtual_entries(),
                               function(airport) {
          return airport.value == id;
        });
        if(virtual) {
          return virtual;
        } else {
          return $.detect(this.find_all_real_entries(), function(airport) {
            return airport.value == id;
          });
        }
      }
    },
    find_entry_by_element_dlc: function(element_dlc) {
      if(element_dlc == this.find_default_entry().dlc) {
        return this.find_default_entry();
      } else {
        return $.detect(this.find_all_real_entries(), function(airport) {
          return airport.dlc == element_dlc;
        });
      }
    },
    underscore_class_name: 'departure_airport',
    tt_key: 'abflughafen'
  }
});
SearchMask.DepartureAirport.Entry = new JS.Class({
  initialize: function(name, value) {
    this.name = name;
    this.value = value;
  },
  element_id: function() {
    return 'airport_' + this.value;
  }
});
SearchMask.DepartureAirport.DefaultEntry = new JS.Class(
  SearchMask.DepartureAirport.Entry, {
  initialize: function() {
    this.callSuper('Alle', -1);
  }
});
SearchMask.DepartureAirport.VirtualEntry = new JS.Class(
  SearchMask.DepartureAirport.Entry, {
  initialize: function(name, value, associated_ids) {
    this.callSuper(name, value);
    this.associated_ids = associated_ids;
  },
  has_associated_airport_with_key: function(key) {
    var detected = $.detect(this.associated_ids,
                            function(k) {return k == key;});
    return detected !== null;
  },
  extend: {
    fetch_entries: function() {
      return [
        new this('Nord', 5000, [8, 37, 15, 21, 20, 31, 29, 40, 4, 43, 5]),
        new this('Süd', 5001, [14, 17, 24, 90, 15, 16, 29, 36, 38, 41, 45, 48]),
        new this('West', 5002,
                 [28, 10, 12, 14, 24, 37, 15, 21, 16, 39, 41, 48]),
        new this('Ost', 5003, [0, 11, 14, 15, 29, 38, 40, 4, 43, 5])
      ];
    }
  }
});
SearchMask.DepartureAirport.RealEntry = new JS.Class(
  SearchMask.DepartureAirport.Entry, {
  initialize: function(name, value, dlc, pos_y, pos_x) {
    this.callSuper(name, value);
    this.dlc = dlc;
    this.pos_x = pos_x;
    this.pos_y = pos_y;
  },
  extend: {
    fetch_entries: function() {
      return [
        new this('Altenburg-Nobitz', 0, 'AOC', 200, 220),
        new this('Amsterdam (NL)', 1, 'AMS', 131, 44),
        new this('Basel-Mulhouse (CH)', 3, 'BSL', 348, 84),
        new this('Berlin-Schönefeld', 4, 'SXF', 139, 228),
        new this('Berlin-Tegel', 5, 'TXL', 123, 215),
        new this('Billund (DK)', 94, 'BLL', 2, 124),
        new this('Bremen', 8, 'BRE', 113, 124),
        new this('Brüssel (B)', 9, 'BRU', 211, 4),
        new this('Dortmund', 10, 'DTM', 178, 98),
        new this('Dresden', 11, 'DRS', 190, 248),
        new this('Düsseldorf', 12, 'DUS', 193, 72),
        new this('Eindhoven (NL)', 73, 'EIN', 169, 34),
        new this('Enschede (NL)', 13, 'ENS', 145, 59),
        new this('Erfurt', 14, 'ERF', 206, 180),
        new this('Frankfurt', 15, 'FRA', 236, 130),
        new this('Frankfurt-Hahn', 16, 'HHN', 241, 90),
        new this('Friedrichshafen', 17, 'FDH', 336, 140),
        new this('Genf (CH)', 18, 'GVA', 388, 48),
        new this('Graz (A)', 19, 'GRZ', 342, 288),
        new this('Groningen (NL)', 81, 'GRQ', 111, 64),
        new this('Hamburg', 20, 'HAM', 97, 154),
        new this('Hannover', 21, 'HAJ', 142, 144),
        new this('Innsbruck (A)', 23, 'INN', 358, 184),
        new this('Karlsruhe', 24, 'FKB', 282, 114),
        new this('Klagenfurt (A)', 27, 'KLU', 356, 258),
        new this('Köln-Bonn', 28, 'CGN', 208, 84),
        new this('Leipzig/Halle', 29, 'LEJ', 180, 210),
        new this('Linz (A)', 30, 'LNZ', 316, 254),
        new this('Lübeck', 31, 'LBC', 84, 166),
        new this('Lüttich (B)', 32, 'LGG', 211, 41),
        new this('Luxemburg (LU)', 33, 'LUX', 252, 41),
        new this('Maastricht-Aachen (NL)', 34, 'MST', 194, 9),
        new this('Memmingen', 90, 'FMM', 320, 160),
        new this('München', 36, 'MUC', 312, 194),
        new this('Münster-Osnabrück', 37, 'FMO', 158, 106),
        new this('Niederrhein (Weeze)', 49, 'NRN', 171, 54),
        new this('Nürnberg', 38, 'NUE', 272, 180),
        new this('Paderborn', 39, 'PAD', 173, 125),
        new this('Rostock', 40, 'RLG', 76, 200),
        new this('Saarbrücken', 41, 'SCN', 263, 64),
        new this('Salzburg (A)', 42, 'SZG', 324, 234),
        new this('Schwerin', 43, 'ZSR', 95, 181),
        new this('Strasbourg (F)', 44, 'SXB', 302, 82),
        new this('Stuttgart', 45, 'STR', 295, 140),
        new this('Warschau (PL)', 77, 'WAW', 117, 328),
        new this('Wien (A)', 46, 'VIE', 312, 326),
        new this('Zürich (CH)', 47, 'ZRH', 345, 102),
        new this('Zweibrücken', 48, 'ZQW', 270, 84)
      ];
    }
  }
});


SearchMask.Destination = new JS.Class(SearchMask.FinderLogic, {
  initialize: function(entry) {
    this.entry = entry;
  },
  put_to_form: function(form) {
    this.form_state.destination_autocompleter.set_value(this.entry.value);
  },
  to_url_params: function() {
    return this.entry.to_url_params();
  },
  get_value: function() {
    return this.form_state.destination_autocompleter.value;
  },
  extend: {
    default_entry: function() {
      return new this(this.find_all_countries()[0]);
    },
    element_selector: '#destination_id',
    underscore_class_name: 'destination',
    find_by_id: function(id) {
      var result = null;

      $.each(this.find_all_countries(), function(idx, country) {

        if(country.value == id) {
          result = country;
          return false;
        }

        $.each(country.regions, function(idx2, region) {
          if(region.value == id) {
            result = region;
            return false;
          }
          return true;
        });

        if(result !== null) {
          return false;
        }
        return true;
      });

      return result ? new this(result) : null;
    },
    find_by_form: function(form, form_state) {
      var value = form_state.destination_autocompleter.value;
      return this.find_by_id(value);
    },
    find_all_countries: function() {
      if(typeof(this.all_countries) === 'undefined') {
        this.all_countries = this.Country.fetch_entries();
      }
      return this.all_countries;
    }
  }
});
SearchMask.Destination.Region = new JS.Class({
  initialize: function(name, value) {
    this.name = name;
    this.value = value;
    this.type = this.klass.underscore_class_name;
  },
  to_url_params: function() {
    return { zielgebiets_kenner: this.value, detail: 'hotel' };
  },
  country_name: function() {
    return this.country.name;
  },
  extend: {
    underscore_class_name: 'region'
  }
});
SearchMask.Destination.Country = new JS.Class({
  initialize: function(name, value, regions) {
    var self = this;
    this.name = name;
    this.value = value;
    this.regions = regions;
    this.type = this.klass.underscore_class_name;

    $.each(this.regions, function(idx, region) {
      region.country = self;
    });
  },
  to_url_params: function() {
    return { ziel: this.value, detail: 'zielgebiet' };
  },
  extend: {
    underscore_class_name: 'country',
    fetch_entries: function() {
      var R = SearchMask.Destination.Region;
      return [
        new this('Alle', -1, []),
        new this('Balearen', 10000, [
          new R('Formentera', 93),
          new R('Ibiza', 123),
          new R('Mallorca', 205),
          new R('Menorca', 214)
        ]),
        new this('Kanaren', 10001, [
          new R('Fuerteventura', 96),
          new R('Gran Canaria', 106),
          new R('La Gomera', 181),
          new R('La Palma', 182),
          new R('Lanzarote', 185),
          new R('Teneriffa', 351)
        ]),
        new this('Portugal', 10002, [
          new R('Alentejo', 11),
          new R('Algarve', 12),
          new R('Azoren', 25),
          new R('Costa da Caparica', 61),
          new R('Costa de Prata', 63),
          new R('Costa do Estoril', 65),
          new R('Costa Verde', 68),
          new R('Festland', 89),
          new R('Lissabon & Umgebung', 194),
          new R('Madeira', 201),
          new R('Pico (Azoren)', 275),
          new R('Porto', 281)
        ]),
        new this('Spanisches Festland', 10003, [
          new R('Barcelona & Umgebung', 32),
          new R('Costa Blanca', 59),
          new R('Madrid & Umgebung', 202),
          new R('Costa Brava', 60),
          new R('Nordspanien - Atlantikküste', 98),
          new R('Costa de la Luz', 62),
          new R('Zentral Spanien', 388),
          new R('Costa Dorada', 66),
          new R('Golf von Almeria', 104),
          new R('Costa del Sol', 64),
          new R('Costa Azahar', 58)
        ]),
        new this('Türkei', 10004, [
          new R("Antalya & Belek", 17),
          new R("Ayvalik, Cesme & Izmir", 53),
          new R("Bodrum", 112),
          new R("Dalaman - Fethiye - Oeludeniz", 70),
          new R("Istanbul & Umgebung", 150),
          new R("Kemer & Beldibi", 168),
          new R("Kusadasi & Didyma", 178),
          new R("Marmaris & Icmeler", 207),
          new R("Mersin - Adana - Antakya", 689),
          new R("Side & Alanya", 324),
          new R("Türkei Inland", 126)
        ]),
        new this('Griechische Inseln', 10005, [
          new R("Aegina", 5),
          new R("Alonissos", 14),
          new R("Amorgos", 15),
          new R("Andros", 16),
          new R("Chios", 56),
          new R("Euböa (Evia)", 672),
          new R("Folegandros", 92),
          new R("Hydra, Spetses", 122),
          new R("Ikaria", 124),
          new R("Kalymnos", 161),
          new R("Karpathos", 164),
          new R("Kefalonia", 167),
          new R("Korfu", 172),
          new R("Kos", 174),
          new R("Kreta", 175),
          new R("Lefkas & Meganissi", 187),
          new R("Leros", 188),
          new R("Lesbos", 189),
          new R("Mykonos", 228),
          new R("Naxos", 230),
          new R("Paros, Serifos & Sifnos", 269),
          new R("Patmos", 270),
          new R("Poros", 280),
          new R("Rhodos", 295),
          new R("Samos", 308),
          new R("Santorin", 310),
          new R("Skiathos & Skopelos", 331),
          new R("Symi", 347),
          new R("Syros", 329),
          new R("Thassos", 357),
          new R("Tilos", 361),
          new R("Tinos", 362),
          new R("Zakynthos", 387),
          new R("weitere Angebote Griechische Inseln", 415)
        ]),
        new this("Griechenland Festland", 10006, [
          new R("Athen & Umgebung", 23),
          new R("Chalkidiki", 54),
          new R("Epiros", 87),
          new R("Makedonien", 748),
          new R("Olympische Riviera", 673),
          new R("Peloponnes", 271),
          new R("Pilion", 113),
          new R("Thessalien", 747),
          new R("Thessaloniki", 358),
          new R("Thrakien", 674)
        ]),
        new this("Italien Malta", 10007, [
          new R("Abruzzen", 0),
          new R("Aostatal & Piemont & Lombardei", 276),
          new R("Apulien", 21),
          new R("Basilikata", 683),
          new R("Capri", 50),
          new R("Dolomiten", 74),
          new R("Elba", 82),
          new R("Emilia Romagna", 85),
          new R("Friaul - Julisch Venetien", 686),
          new R("Gardasee", 100),
          new R("Ischia", 147),
          new R("Kalabrien", 159),
          new R("Marken", 685),
          new R("Malta", 206),
          new R("Neapel & Umgebung", 231),
          new R("Oberitalienische Seen", 256),
          new R("Rom & Umgebung", 299),
          new R("Sardinien", 311),
          new R("Sizilien", 330),
          new R("Toscana", 365),
          new R("Umbrien", 369),
          new R("Venetien", 374)
        ]),
        new this("Tunesien, Marokko", 10008, [
          new R("Marokko - Agadir", 6),
          new R("Marokko - Marrakesch", 208),
          new R("Marokko - Norden", 404),
          new R("Tunesien - Hammamet", 115),
          new R("Tunesien - Inland", 129),
          new R("Tunesien - Insel Djerba", 133),
          new R("Tunesien - Monastir", 221),
          new R("Tunesien - Norden", 246),
          new R("Tunesien - Oase Tozeur", 253),
          new R("Tunesien - Oase Zarzis", 254)
        ]),
        new this("Ägypten", 10010, [
          new R("Hurghada & Safaga", 121),
          new R("Kairo & Gizeh & Memphis", 158),
          new R("Luxor & Assuan", 198),
          new R("Marsa Matruh & Alexandria", 791),
          new R("Marsa Alam & Quseir", 287),
          new R("Sharm el Sheikh / Nuweiba / Taba", 327),
          new R("weitere Angebote Aegypten", 420)
        ]),
        new this("Afrika", 10011, [
          new R("Aethiopien", 756),
          new R("Gambia", 99),
          new R("Johannesburg & Umgebung", 156),
          new R("Kap Verde - Boavista", 40),
          new R("Kap Verde - Sal", 305),
          new R("Kenia - Nordküste", 248),
          new R("Kenia - Südküste", 342),
          new R("Mozambique", 520),
          new R("Malawi", 737),
          new R("Madagaskar", 584),
          new R("Namibia", 229),
          new R("Nordwesten", 495),
          new R("Tansania - Sansibar", 349),
          new R("Kapstadt & Umgebung", 163)
        ]),
        new this("Kuba", 10012, [
          new R("Kuba (Holguin)", 118),
          new R("Kuba - Varadero & Havanna", 373)
        ]),
        new this("Dom. Republik", 10013, [
          new R("Dom. Republik - Norden (Puerto Plata & Samana)", 400),
          new R("Dom. Republik - Süden (Santo Domingo)", 75),
          new R("Dom. Republik - Osten (Punta Cana)", 401)
        ]),
        new this("Karibik", 10014, [
          new R("Antigua & Barbuda", 18),
          new R("Bahamas", 27),
          new R("Barbados", 31),
          new R("Bermuda", 38),
          new R("Cayman Inseln", 52),
          new R("Curacao & Aruba & Bonaire", 240),
          new R("Grenada", 108),
          new R("Guadeloupe", 109),
          new R("Isla Margarita", 148),
          new R("Jamaika", 153),
          new R("Martinique", 209),
          new R("Puerto Rico", 284),
          new R("St.Lucia", 337),
          new R("St. Marteen (nl.) & St.Eustatius & Saba", 754),
          new R("St. Martin (frz.)", 741),
          new R("Tobago", 363),
          new R("Turks & Caicos Inseln", 368)
        ]),
        new this("USA", 10015, [
          new R("Alaska", 9),
          new R("Florida Ostküste", 263),
          new R("Florida Westküste", 384),
          new R("Hawaii - Insel Oahu", 141),
          new R("Kalifornien", 160),
          new R("Nevada", 186),
          new R("New Jersey", 235),
          new R("New York", 237),
          new R("Orlando (Florida)", 260),
          new R("Rundreise USA", 640)
        ]),
        new this("Mexico", 10016, [
          new R("Acapulco / Oaxaca", 2),
          new R("Inland", 490),
          new R("Mexiko", 215),
          new R("Mexiko Stadt & Umgebung", 216),
          new R("Yucatan / Cancun", 386)
        ]),
        new this("Asien", 10017, [
          new R("Singapur", 328),
          new R("Tokio, Osaka, Hiroshima, Japan. Inseln", 364),
          new R("Nepal", 232),
          new R("Philippinen", 274),
          new R("Indonesien", 687),
          new R("Myanmar", 227),
          new R("Vietnam", 376),
          new R("Indonesien: Bali", 29),
          new R("Sri Lanka", 334),
          new R("Malaysia", 203),
          new R("Usbekistan", 496),
          new R("China", 55),
          new R("Taipeh & Umgebung", 480),
          new R("Indonesien: Insel Bintan", 131),
          new R("Hongkong & Umgebung", 119),
          new R("Philippinen: Luzon & Manila", 487),
          new R("Indonesien: Sunda-Inseln", 345),
          new R("Philippinen: Region Cebu & Borocay", 488)
        ]),
        new this("Australien", 10018, [
          new R("Queensland", 286)
        ]),
        new this("Zypern", 10019, [
          new R("Republik Zypern (Süden)", 390),
          new R("Türkische Republik Zypern (Norden)", 736),
          new R("Zypern", 10019),
          new R("weitere Angebote Griechenland, Zypern", 416)
        ]),
        new this("Dubai, Arabische Halbinsel", 10020, [
          new R("Abu Dhabi", 1),
          new R("Ajman", 7),
          new R("Al Ain", 8),
          new R("Dubai", 76),
          new R("Fujairah", 97),
          new R("Katar", 166),
          new R("Oman", 258),
          new R("Ras Al-Khaimah", 288),
          new R("Sharjah / Khorfakkan", 323),
          new R("Umm Al Quwain", 449)
        ]),
        new this("Frankreich", 10021, [
          new R("Atlantikküste", 24),
          new R("Côte d'Azur", 69),
          new R("Disneyland Paris", 73),
          new R("Elsass / Lothringen", 84),
          new R("Französische Alpen", 95),
          new R("Frankreich Osten", 261),
          new R("Korsika", 173),
          new R("Monaco", 220),
          new R("Mittelmeerküste", 219),
          new R("Normandie & Nordküste", 742),
          new R("Provence-Alpes-Côte d'Azur", 283),
          new R("Paris & Umgebung", 268),
          new R("weitere Angebote Frankreich", 431)
        ]),
        new this("Nordeuropa", 10022, [
          new R("Dänemark", 72),
          new R("Finnland", 91),
          new R("Island", 149),
          new R("Norwegen", 251),
          new R("Schweden", 456)
        ]),
        new this("Südamerika", 10023, [
          new R("Argentinien", 443),
          new R("Brasilien", 660),
          new R("Brasilien: Recife", 289),
          new R("Brasilien: Rio de Janeiro & Umgebung", 298),
          new R("Ecuador", 469),
          new R("Peru", 470),
          new R("Kolumbien", 665)
        ]),
        new this("Kanada", 10024, [
          new R("Alberta", 10),
          new R("British Columbia", 46),
          new R("Nova Scotia", 252),
          new R("Quebec", 285),
          new R("Ontario", 259)
        ]),
        new this("Naher Osten", 10026, [
          new R("Israel", 682),
          new R("Jerusalem & Umgebung", 155),
          new R("Jordanien", 157),
          new R("Libanon", 191),
          new R("Totes Meer", 366),
          new R("Tel Aviv & Umgebung", 350)
        ]),
        new this("Thailand", 10027, [
          new R("Bangkok & Umgebung", 30),
          new R("Insel Ko Samui", 136),
          new R("Inseln in der Andaman See (Koh Pee Pee, Koh Lanta)", 355),
          new R("Inseln im Golf von Thailand (Koh Chang, Koh Phangan)",
                356, 323),
          new R("Insel Phuket", 142),
          new R("Khao Lak & Umgebung", 169),
          new R("Krabi & Umgebung", 783),
          new R("Norden (Chiang Mai, Chiang Rai, Sukhothai)", 778),
          new R("Süden (Surat Thani, Trang)", 782),
          new R("Südosten (Pattaya, Jomtien)", 781),
          new R("Westen (Hua Hin, Cha Am, River Kwai)", 780),
          new R("sonstige Angebote Thailand", 437)
        ]),
        new this("Mitteleuropa", 10028, [
          new R("Tirol - Innsbruck, Mittel- und Nordtirol", 408),
          new R("Steiermark", 409),
          new R("Belgien", 36),
          new R("Zürich", 394),
          new R("St.Gallen", 335),
          new R("Bern & Berner Oberland", 39),
          new R("Salzburg - Salzkammergut", 307),
          new R("Salzburg - Salzburger Land", 306),
          new R("Tirol - Stubaital", 338),
          new R("Waadt", 393),
          new R("Niederösterreich", 406),
          new R("Kärnten", 405),
          new R("Basel", 392),
          new R("London & Südengland", 391),
          new R("Uri", 371),
          new R("Tirol - Zillertal", 389),
          new R("Irland", 146),
          new R("Niederlande", 241),
          new R("Luzern", 199),
          new R("Burgenland", 403),
          new R("Salzburg - Salzburg", 402),
          new R("Schwyz", 319),
          new R("Mittel- & Nordengland", 498),
          new R("Vorarlberg - sonstige Angebote", 442),
          new R("Tirol - Westtirol & Oetztal", 266),
          new R("Schottland", 315),
          new R("Schweiz", 318),
          new R("Genf", 462),
          new R("Oberösterreich", 407),
          new R("Graubünden", 107),
          new R("Tirol - Region Seefeld", 320),
          new R("Wien & Umgebung", 395)
        ]),
        new this("Deutschland", 10029, [
          new R("Allgäu", 13),
          new R("Baden-Württemberg", 26),
          new R("Bayerischer Wald", 34),
          new R("Bayerische Alpen", 33),
          new R("Berchtesgadener Land", 396),
          new R("Bremen", 44),
          new R("Brandenburg", 43),
          new R("Berlin", 37),
          new R("Düsseldorf & Umgebung", 78),
          new R("Deutschland - sonstige Angebote", 655),
          new R("Franken", 94),
          new R("Hamburg", 114),
          new R("Hessen", 117),
          new R("Hunsrück / Taunus", 120),
          new R("Köln & Umgebung", 171),
          new R("Lüneburger Heide", 196),
          new R("München", 656),
          new R("Münsterland", 399),
          new R("Mecklenburg Ostseeküste", 211),
          new R("Mecklenburgische Seenplatte", 212),
          new R("Mecklenburg-Vorpommern", 213),
          new R("Nordrhein-Westfalen", 249),
          new R("Niedersachsen", 242),
          new R("Niederbayern", 239),
          new R("Oberpfalz", 35),
          new R("Oberbayern", 255),
          new R("Ruhrgebiet", 300),
          new R("Sachsen", 303),
          new R("Sachsen-Anhalt", 304),
          new R("Schleswig-Holstein", 746)
        ]),
        new this("Kroatien, Bulgarien, Osteuropa", 10030, [
          new R("Adria", 4),
          new R("Bukarest & Umgebung", 502),
          new R("Bulgarien (Goldstrand)", 103),
          new R("Bulgarien (Landesinnere)", 183),
          new R("Bulgarien (Sonnenstrand)", 333),
          new R("Insel Brac", 132),
          new R("Insel Hvar", 134),
          new R("Insel Krk", 137),
          new R("Istrien", 151),
          new R("Kvarner Bucht", 180),
          new R("Kroatische Inseln", 177),
          new R("Moskau & Umgebung", 225),
          new R("Mittelkroatien", 675),
          new R("Mitteldalmatien", 218),
          new R("Norddalmatien", 244),
          new R("Polen", 278),
          new R("Riga", 297),
          new R("Rumänien", 301),
          new R("Sankt Petersburg & Umgebung", 499),
          new R("Serbien, Montenegro", 223),
          new R("Slowenien Inland", 128),
          new R("Süddalmatien", 339),
          new R("Tschechien", 367),
          new R("Ungarn", 370)
        ]),
        new this("Glückshotels", 10032, [
          new R("Glückshotel Bulgarien", 632),
          new R("Glückshotel Costa del Sol", 561),
          new R("Glückshotel Costa de la Luz", 563),
          new R("Glückshotel Dominikanische Republik", 423),
          new R("Glückshotel Dubai & Arabische Halbinsel", 591),
          new R("Glückshotel Fuerteventura", 553),
          new R("Glückshotel Gardasee", 290),
          new R("Glückshotel Gran Canaria", 554),
          new R("Glückshotel Griechenland", 613),
          new R("Glückshotel Ischia", 625),
          new R("Glückshotel Italien", 621),
          new R("Glückshotel Jamaika", 745),
          new R("Glückshotel Kalabrien", 623),
          new R("Glückshotel Kroatien", 135),
          new R("Glückshotel Kreta", 571),
          new R("Glückshotel Kuba", 419),
          new R("Glückshotel Lanzarote", 557),
          new R("Glückshotel Madeira", 593),
          new R("Glückshotel Malediven", 667),
          new R("Glückshotel Mallorca", 411),
          new R("Glückshotel Malta", 622),
          new R("Glückshotel Marokko", 577),
          new R("Glückshotel Mexiko", 630),
          new R("Glückshotel Portugal", 594),
          new R("Glückshotel Spanische Küste - Festland", 560),
          new R("Glückshotel Sardinien", 619),
          new R("Glückshotel Türkei", 546),
          new R("Glückshotel Türkische Riviera", 548)
        ]),
        new this("Rundreisen", 10033, [
          new R("Rundreise Aegypten", 540),
          new R("Rundreise Andalusien", 564),
          new R("Rundreise Arabische Halbinsel", 430),
          new R("Rundreise Azoren", 595),
          new R("Rundreise Brasilien", 523),
          new R("Rundreise Bulgarien", 631),
          new R("Rundreise Costa Rica", 641),
          new R("Rundreise Djerba", 653),
          new R("Rundreise Ecuador", 668),
          new R("Rundreise Griechenland", 612),
          new R("Rundreise Indonesien", 418),
          new R("Rundreise Island", 326),
          new R("Rundreise Italien", 618),
          new R("Rundreise Jamaika", 424),
          new R("Rundreise Jordanien", 587),
          new R("Rundreise Kalabrien", 620),
          new R("Rundreise Kanada", 599),
          new R("Rundreise Kenia", 585),
          new R("Rundreise Kreta", 567),
          new R("Rundreise Kuba", 413),
          new R("Rundreise La Reunion", 421),
          new R("Rundreise Madeira", 592),
          new R("Rundreise Malta", 616),
          new R("Rundreise Marokko", 642),
          new R("Rundreise Mexiko", 629),
          new R("Rundreise Naher Osten", 740),
          new R("Rundreise Namibia", 644),
          new R("Rundreise Oman", 455),
          new R("Rundreise Peru - Südamerika", 636),
          new R("Rundreise Portugal", 412),
          new R("Rundreise Rumänien", 566),
          new R("Rundreise Sardinien", 617),
          new R("Rundreise Sizilien", 615),
          new R("Rundreise Spanien", 677),
          new R("Rundreise Sri Lanka", 453),
          new R("Rundreise Südamerika", 433),
          new R("Rundreise Südafrika", 583),
          new R("Rundreise Tansania", 586),
          new R("Rundreise Thailand", 588),
          new R("Rundreise Trinidad & Tobago", 790),
          new R("Rundreise Tunesien", 542),
          new R("Rundreise Türkei", 545),
          new R("Rundreise Venezuela", 522),
          new R("Rundreise Vietnam", 597),
          new R("Rundreise Zakynthos", 649),
          new R("Rundreise Zypern", 429)
        ]),
        new this("Kreuzfahrten", 10034, [
          new R("Fluß- & Kreuzfahrten Russland", 776),
          new R("Kreuzfahrt & Hotel Türkei", 550),
          new R("Kreuzfahrten Arabische Halbinsel", 766),
          new R("Kreuzfahrten Mallorca", 764),
          new R("Kreuzfahrten Nordland", 770),
          new R("Kreuzfahrt Region Mittelmeer", 669),
          new R("Kreuzfahrt Region Karibik", 543),
          new R("Kreuzfahrt Türkei", 544),
          new R("Nilkreuzfahrten", 539),
          new R("weitere Kreuzfahrten", 524)
        ]),
        new this("", 10035, [
          new R("Fly & Drive Algarve", 694),
          new R("Fly & Drive Azoren", 696),
          new R("Fly & Drive Costa Blanca", 697),
          new R("Fly & Drive Costa de la Luz", 698),
          new R("Fly & Drive Costa del Sol", 699),
          new R("Fly & Drive Florida", 700),
          new R("Fly & Drive Fuerteventura", 701),
          new R("Fly & Drive Golf von Almeria", 703),
          new R("Fly & Drive Italien", 721),
          new R("Fly & Drive Kalabrien", 705),
          new R("Fly & Drive Kuba", 730),
          new R("Fly & Drive Lanzarote", 709),
          new R("Fly & Drive La Palma", 708),
          new R("Fly & Drive Lissabon & Umgebung", 710),
          new R("Fly & Drive Madeira", 711),
          new R("Fly & Drive Mallorca", 712),
          new R("Fly & Drive Menorca", 714),
          new R("Fly & Drive Spanien", 733),
          new R("Fly & Drive USA", 724)
        ]),
        new this("Indischer Ozean", 10036, [
          new R("Malediven", 204),
          new R("Mauritius", 210),
          new R("Reunion", 291),
          new R("Seychellen", 322)
        ]),
        new this("Mittelamerika", 10037, [
          new R("Costa Rica", 67),
          new R("Guatemala", 110),
          new R("Honduras", 486),
          new R("Panama", 267)
        ]),
        new this("Fly & Stay", 10038, [
          new R("Fly & Stay Afrika", 784),
          new R("Fly & Stay Amerika & Kanada", 787),
          new R("Fly & Stay Asien", 785),
          new R("Fly & Stay Europa", 786)
        ])
      ];
    }
  }
});

SearchMask.DestinationEarth = new JS.Class(SearchMask.Destination, {
  extend: {
    find_by_hotelbits: function(bit1, bit2) {
      var countries = $.select_by_bits(this.Country.fetch_entries(),
                                       bit1,
                                       bit2);
      countries = $.map(countries, function(o) {
        return o.select_regions_by_hotelbits(bit1, bit2);
      });
      return countries;
    }
  }
});
SearchMask.DestinationEarth.Region = new JS.Class(SearchMask.Destination.Region,
                                                  {
  initialize: function(name, value, hotelbit1, hotelbit2) {
    this.callSuper(name, value);
    this.hotelbit1 = hotelbit1;
    this.hotelbit2 = hotelbit2;
  }
});
SearchMask.DestinationEarth.Country =
  new JS.Class(SearchMask.Destination.Country, {

  initialize: function(name, value, hotelbit1, hotelbit2, regions) {
    this.callSuper(name, value, regions);
    this.hotelbit1 = hotelbit1;
    this.hotelbit2 = hotelbit2;
  },
  select_regions_by_hotelbits: function(bit1, bit2) {
    var regs = $.select_by_bits(this.regions, bit1, bit2);
    this.regions = regs;
    return this;
  },
  extend: {

    fetch_entries: function() {
      var big_val = Math.pow(2,20)-1;
      var R = SearchMask.DestinationEarth.Region;
      return [
        new this('Alle', -1, big_val, big_val, []),
        new this("Deutschland Nord", 30000, 925536, 1075869567, [
          new R("Bremen", 44, 527616, 40),
          new R("Hamburg", 114, 527616, 874),
          new R("Nordfriesland & Inseln", 314, 793856, 2101318),
          new R("Borkum", 452, 531456, 4100),
          new R("Lüneburger Heide", 196, 527648, 4214),
          new R("Nordseeküste und Inseln - sonstige Angebote", 250, 531712,
                5958),
          new R("Niedersachsen", 242, 531712, 18286),
          new R("Ostseeküste", 264, 662848, 30582),
          new R("Emsland", 86, 3072, 100),
          new R("Schleswig-Holstein", 746, 531520, 1912),
          new R("Harz", 116, 528128, 1073741927)
        ]),
        new this("Deutschland Ost", 30001, 794368, 1077041007, [
          new R("Mecklenburg Ostseeküste", 211, 793856, 1076892526),
          new R("Insel Usedom", 144, 531712, 1073745990),
          new R("Sachsen", 303, 528128, 878),
          new R("Thüringer Wald", 360, 527872, 71),
          new R("Erzgebirge", 88, 527872, 18279),
          new R("Mecklenburgische Seenplatte", 212, 790272, 1077023079),
          new R("Berlin", 37, 527360, 1898),
          new R("Insel Rügen", 143, 531456, 1073746246),
          new R("Mecklenburg-Vorpommern", 213, 531456, 96),
          new R("Brandenburg", 43, 527616, 22375),
          new R("Elbsandsteingebirge", 83, 527616, 1892),
          new R("Sachsen-Anhalt", 304, 527360, 864),
          new R("Thüringen", 359, 527360, 110)
        ]),
        new this("Deutschland Süd", 30002, 790404, 1073766271, [
          new R("Allgäu", 13, 528132, 1073741943),
          new R("Oberbayern", 255, 528128, 871),
          new R("München", 656, 527360, 107),
          new R("Bayerischer Wald", 34, 528128, 1073742695),
          new R("Schwarzwald", 317, 790400, 1073746047),
          new R("Bodensee", 41, 527616, 4199),
          new R("Fichtelgebirge", 90, 528128, 101),
          new R("Baden-Württemberg", 26, 528260, 127),
          new R("Berchtesgadener Land", 396, 3840, 839),
          new R("Hochschwarzwald", 755, 528128, 1073741927),
          new R("Schwäbische Alb", 316, 3072, 1856),
          new R("Bayerische Alpen", 33, 528128, 4167),
          new R("Franken", 94, 527616, 20334),
          new R("Niederbayern", 239, 528128, 20327),
          new R("Oberpfalz", 35, 3840, 1073741926)
        ]),
        new this("Deutschland West", 30003, 790424, 1073746815, [
          new R("Düsseldorf & Umgebung", 78, 527360, 876),
          new R("Eifel & Westerwald", 79, 528144, 84),
          new R("Mosel", 224, 527616, 1073742694),
          new R("Spessart - Odenwald", 451, 3328, 96),
          new R("Köln & Umgebung", 171, 527632, 890),
          new R("Hessisches Bergland", 398, 527872, 68),
          new R("Saarland", 302, 527360, 74),
          new R("Nordrhein-Westfalen", 249, 527768, 126),
          new R("Hunsrück / Taunus", 120, 3328, 4162),
          new R("Rhön", 296, 528128, 68),
          new R("Rheinland-Pfalz", 294, 527616, 98),
          new R("Rheinland", 293, 527376, 92),
          new R("Hessen", 117, 527616, 366),
          new R("Teutoburger Wald", 353, 527616, 96),
          new R("Sauerland", 313, 790016, 71),
          new R("Rheingau", 292, 3072, 107),
          new R("Pfalz", 273, 527616, 110),
          new R("Münsterland", 399, 3072, 40),
          new R("Ruhrgebiet", 300, 527880, 122)
        ]),
        new this("Oesterreich", 30004, 822016, 1080170351, [
          new R("Niederösterreich", 406, 559360, 4199),
          new R("Salzburg - Salzkammergut", 307, 559872, 1073746759),
          new R("Tirol - Zillertal", 389, 559872, 1073746789),
          new R("Salzburg - Salzburger Land", 306, 559872, 1073873255),
          new R("Tirol - Region Seefeld", 320, 559872, 1073747815),
          new R("Tirol - Innsbruck, Mittel- und Nordtirol", 408, 822016,
                1073747823),
          new R("Salzburg - Salzburg", 402, 34816, 40),
          new R("Kärnten", 405, 822016, 1075976039),
          new R("weitere Angebote Oesterreich", 262, 0, 0),
          new R("Steiermark", 409, 559872, 4194671),
          new R("Burgenland", 403, 559360, 4166),
          new R("Tirol - Stubaital", 338, 35328, 1073743719),
          new R("Wien & Umgebung", 395, 559104, 106),
          new R("Tirol - Westtirol & Oetztal", 266, 559872, 1895),
          new R("Vorarlberg - Kleinwalsertal", 170, 559616, 103),
          new R("Tirol - Osttirol", 265, 35328, 71),
          new R("Vorarlberg - sonstige Angebote", 442, 559872, 4455),
          new R("Oberösterreich", 407, 559872, 131431)
        ]),
        new this("Schweiz", 30005, 527104, 1073877359, [
          new R("Basel", 392, 2048, 106),
          new R("Bern & Berner Oberland", 39, 527104, 111),
          new R("Graubünden", 107, 527104, 1073873255),
          new R("St.Gallen", 335, 527104, 103),
          new R("Waadt", 393, 2560, 4175),
          new R("Wallis", 380, 527104, 1073741927),
          new R("Schwyz", 319, 2560, 4165),
          new R("Tessin", 352, 2304, 71),
          new R("Schweiz", 318, 2048, 64),
          new R("Freiburg", 507, 2560, 37),
          new R("Genf", 462, 0, 40),
          new R("Luzern", 199, 526848, 4207),
          new R("Uri", 371, 512, 0),
          new R("Zürich", 394, 526336, 42),
          new R("Obwalden", 257, 2816, 65)
        ]),
        new this("Benelux", 30006, 527104, 4206, [
          new R("Luxemburg", 197, 0, 10),
          new R("Belgien", 36, 526592, 4206),
          new R("Niederlande", 241, 527104, 4206)
        ]),
        new this("Skandinavien", 30007, 527106, 4223, [
          new R("Grönland", 678, 0, 0),
          new R("Finnland", 91, 524288, 104),
          new R("Dänemark", 72, 526594, 4220),
          new R("Lappland", 690, 526336, 36),
          new R("Norwegen", 251, 527104, 4201),
          new R("Schweden", 456, 527104, 4202)
        ]),
        new this("Italien", 30008, 928512, 1200783215, [
          new R("Sizilien", 330, 796928, 109056366),
          new R("Neapel & Umgebung", 231, 534784, 4462),
          new R("Sardinien", 311, 928000, 33558886),
          new R("weitere Angebote Italien, Malta", 417, 8192, 0),
          new R("Capri", 50, 10240, 4162),
          new R("Oberitalienische Seen", 256, 535296, 4167),
          new R("Rom & Umgebung", 299, 665856, 4206),
          new R("Aostatal & Piemont & Lombardei", 276, 534784, 4206),
          new R("Gardasee", 100, 534784, 1073746023),
          new R("Marken", 685, 10240, 4165),
          new R("Venetien", 374, 796928, 1073774446),
          new R("Ischia", 147, 10240, 33569632),
          new R("Umbrien", 369, 10496, 358),
          new R("Toscana", 365, 534784, 1073747823),
          new R("Basilikata", 683, 10240, 292),
          new R("Kalabrien", 159, 10240, 117444965),
          new R("Ligurien", 192, 10496, 4204),
          new R("Italienische Alpen", 152, 2560, 1),
          new R("Abruzzen", 0, 272640, 4196),
          new R("Apulien", 21, 796928, 127012966),
          new R("Südtirol & Norditalien", 344, 535296, 1073742183),
          new R("Friaul - Julisch Venetien", 686, 534784, 4204),
          new R("Dolomiten", 74, 11008, 101),
          new R("Elba", 82, 2304, 4420),
          new R("Emilia Romagna", 85, 534784, 4460)
        ]),
        new this("Frankreich", 30009, 665857, 4479, [
          new R("Französische Alpen", 95, 8192, 5),
          new R("Languedoc Roussillon", 184, 10240, 78),
          new R("weitere Angebote Frankreich", 431, 526592, 104),
          new R("Paris & Umgebung", 268, 526337, 126),
          new R("Burgund", 48, 8192, 66),
          new R("Disneyland Paris", 73, 526593, 276),
          new R("Atlantikküste", 24, 526592, 4462),
          new R("Korsika", 173, 534784, 4422),
          new R("Monaco", 220, 10240, 4170),
          new R("Midi Pyrenees", 774, 2048, 1),
          new R("Limousin", 763, 0, 6),
          new R("Bretagne", 45, 2304, 4166),
          new R("Frankreich Osten", 261, 8192, 100),
          new R("Côte d'Azur", 69, 534784, 4463),
          new R("Elsass / Lothringen", 84, 657664, 110),
          new R("Normandie & Nordküste", 742, 2304, 4196),
          new R("Provence-Alpes-Côte d'Azur", 283, 534784, 110),
          new R("Mittelmeerküste", 219, 526592, 4460)
        ]),
        new this("Spanien", 30010, 4139776, 1334542207, [
          new R("Costa Azahar", 58, 534784, 4196),
          new R("Costa del Sol", 64, 2763520, 1082331503),
          new R("Madrid & Umgebung", 202, 526848, 42),
          new R("Costa Brava", 60, 534784, 4455),
          new R("Golf von Almeria", 104, 2107648, 4132),
          new R("Costa de la Luz", 62, 665856, 1149309294),
          new R("Zentral Spanien", 388, 535040, 105),
          new R("Barcelona & Umgebung", 32, 534528, 528488),
          new R("Costa Dorada", 66, 534784, 4980),
          new R("Nordspanien - Atlantikküste", 98, 526336, 4199),
          new R("La Gomera", 181, 2304, 33558853),
          new R("Lanzarote", 185, 3803392, 1140920676),
          new R("Formentera", 93, 8192, 67178820),
          new R("Gran Canaria", 106, 3803392, 1199658855),
          new R("Fuerteventura", 96, 2230528, 1300436804),
          new R("Graciosa", 105, 0, 0),
          new R("La Palma", 182, 526336, 33558597),
          new R("Teneriffa", 351, 2820352, 1182891879),
          new R("El Hierro", 81, 0, 4160),
          new R("Mallorca", 205, 4139264, 1200314215),
          new R("Ibiza", 123, 4007936, 1191711078),
          new R("Menorca", 214, 534784, 1183322468),
          new R("Costa Blanca", 59, 534784, 4454)
        ]),
        new this("Slowakei / Tschechien", 30011, 527104, 14703, [
          new R("Slowakei", 332, 526848, 4463),
          new R("Tschechien", 367, 527104, 10607)
        ]),
        new this("Polen", 30012, 527104, 4206, [
          new R("Polen", 278, 527104, 4206)
        ]),
        new this("Ungarn", 30013, 527104, 4460, [
          new R("Ungarn", 370, 527104, 4204),
          new R("Plattensee / Balaton", 277, 526592, 4452)
        ]),
        new this("Kroatien", 30014, 927744, 100733294, [
          new R("Norddalmatien", 244, 534528, 67113316),
          new R("Süddalmatien", 339, 665600, 33558638),
          new R("Mittelkroatien", 675, 10240, 40),
          new R("Insel Krk", 137, 534528, 69700),
          new R("Kvarner Bucht", 180, 534528, 33558628),
          new R("Kroatische Inseln", 177, 534528, 4420),
          new R("Insel Brac", 132, 534528, 67113284),
          new R("Insel Hvar", 134, 10240, 4164),
          new R("Istrien", 151, 10240, 4454),
          new R("Mitteldalmatien", 218, 272384, 100667468)
        ]),
        new this("Slowenien", 30015, 527104, 4455, [
          new R("Adria", 4, 526336, 4422),
          new R("Slowenien Inland", 128, 527104, 357)
        ]),
        new this("USA / Kanada", 30016, 543488, 69999, [
          new R("Wyoming", 385, 16384, 0),
          new R("Washington", 381, 18688, 104),
          new R("Nevada", 186, 19200, 106),
          new R("Colorado", 57, 16384, 40),
          new R("Kalifornien: Sierra Nevada", 489, 18944, 101),
          new R("Texas", 354, 18432, 4136),
          new R("Florida Ostküste", 263, 542976, 69990),
          new R("Orlando (Florida)", 260, 542976, 4452),
          new R("New Mexico", 491, 16384, 32),
          new R("Washington D.C. & Maryland", 382, 540672, 40),
          new R("Alabama", 527, 16384, 0),
          new R("Montana", 222, 16384, 0),
          new R("Pennsylvania", 272, 16640, 8),
          new R("Kansas (Wichita)", 528, 16384, 0),
          new R("Kalifornien", 160, 542976, 4206),
          new R("Oregon", 464, 16384, 4160),
          new R("Tennessee", 463, 16384, 32),
          new R("Quebec", 285, 542720, 4200),
          new R("Manitoba", 473, 540672, 0),
          new R("Ontario", 259, 18688, 4200),
          new R("British Columbia", 46, 543488, 4203),
          new R("Nova Scotia", 252, 542720, 4192),
          new R("New Brunswick", 503, 540672, 0),
          new R("Saskatchewan", 312, 16384, 0),
          new R("Prince Edward Island", 282, 16384, 32),
          new R("Yukon", 505, 16384, 32),
          new R("Nordwest Territorien", 506, 16384, 0),
          new R("Neufundland", 233, 16384, 0),
          new R("Alberta", 10, 19200, 104),
          new R("Florida Westküste", 384, 542976, 4452),
          new R("Hawaii - Insel Molokai", 140, 16384, 4160),
          new R("Georgia", 101, 16384, 40),
          new R("Hawaii - Insel Oahu", 141, 18688, 4198),
          new R("Minnesota", 526, 16384, 32),
          new R("Michigan", 217, 16384, 0),
          new R("Indiana", 474, 16384, 0),
          new R("Illinois", 125, 18432, 42),
          new R("Hawaii - Insel Kauai", 466, 18688, 4166),
          new R("South Dakota", 467, 16384, 0),
          new R("Hawaii - Insel Big Island", 459, 18688, 4098),
          new R("Utah", 372, 16384, 42),
          new R("New England", 234, 18688, 4207),
          new R("New Jersey", 235, 16384, 32),
          new R("North Carolina", 457, 16384, 4096),
          new R("Hawaii - Insel Maui", 139, 18688, 4166),
          new R("Hawaii - Insel Lanai", 138, 16384, 0),
          new R("Oklahoma", 525, 16384, 0),
          new R("Florida Südspitze", 343, 542976, 4196),
          new R("Virginia", 379, 16384, 4128),
          new R("Rundreise USA", 640, 16384, 0),
          new R("South Carolina", 465, 18688, 4096),
          new R("New York", 237, 542720, 4458),
          new R("Ohio", 510, 16384, 0),
          new R("Idaho", 435, 16384, 0),
          new R("Arkansas", 662, 16384, 0),
          new R("Arizona", 22, 542976, 111),
          new R("Lousiana (Mississippi)", 195, 16384, 4202),
          new R("Missouri", 425, 16384, 0),
          new R("Alaska", 9, 16384, 96)
        ]),
        new this("Sonstige", 30017, 24576, 0, [
          new R("Fly & Drive Spanien", 733, 8192, 0),
          new R("Fly & Drive USA", 724, 16384, 0),
          new R("Fly & Drive Kuba", 730, 16384, 0)
        ]),
        new this("Australien", 30018, 543488, 4463, [
          new R("New South Wales", 236, 18944, 4458),
          new R("Queensland", 286, 542720, 4455),
          new R("Victoria", 375, 18688, 4396),
          new R("Australien Westen", 383, 18432, 4160),
          new R("weitere Angebote Australien", 428, 16384, 0),
          new R("Australien Norden", 245, 18432, 4192),
          new R("Süden", 340, 18432, 4192)
        ]),
        new this("Liechtenstein", 30019, 2304, 71, [
          new R("Liechtenstein", 521, 2304, 71)
        ]),
        new this("Dubai, Arabische Halbinsel", 30020, 526592, 42996078, [
          new R("Dubai", 76, 526592, 41947246),
          new R("Ras Al-Khaimah", 288, 2304, 8392772),
          new R("Umm Al Quwain", 449, 0, 4160),
          new R("Fujairah", 97, 2048, 1052676),
          new R("Ajman", 7, 2048, 4100),
          new R("Sharjah / Khorfakkan", 323, 2048, 4356),
          new R("Al Ain", 8, 0, 64),
          new R("Abu Dhabi", 1, 2304, 4110)
        ]),
        new this("Türkei", 30021, 4139264, 1335072622, [
          new R("Kemer & Beldibi", 168, 600064, 1300371302),
          new R("Ayvalik, Cesme & Izmir", 53, 10240, 4460),
          new R("Antalya & Belek", 17, 928000, 1333991268),
          new R("Angebote rund um Istanbul", 551, 0, 0),
          new R("Side & Alanya", 324, 4007936, 1335007076),
          new R("Bodrum", 112, 534528, 192942436),
          new R("Marmaris & Icmeler", 207, 534528, 1333793092),
          new R("Istanbul & Umgebung", 150, 526336, 104),
          new R("Dalaman - Fethiye - Oeludeniz", 70, 534528, 1334974276),
          new R("Kusadasi & Didyma", 178, 534528, 4420)
        ]),
        new this("Portugal", 30022, 2624256, 1183012719, [
          new R("Azoren", 25, 2048, 4193),
          new R("Lissabon & Umgebung", 194, 526592, 46),
          new R("Pico (Azoren)", 275, 0, 64),
          new R("Festland", 89, 2560, 97),
          new R("Costa Verde", 68, 526336, 4192),
          new R("Porto", 281, 526336, 4138),
          new R("Costa da Caparica", 61, 2304, 4160),
          new R("Costa de Prata", 63, 526592, 4194),
          new R("Costa do Estoril", 65, 2304, 4452),
          new R("Algarve", 12, 526592, 1182994791),
          new R("Madeira", 201, 2623744, 1115772775),
          new R("Alentejo", 11, 2304, 4192)
        ]),
        new this("Großbritannien / Irland", 30023, 526592, 4463, [
          new R("Mittel- & Nordengland", 498, 2048, 104),
          new R("Guernsey - Kanalinsel", 111, 256, 64),
          new R("Irland", 146, 526592, 4207),
          new R("Jersey - Kanalinsel", 154, 2304, 4166),
          new R("London & Südengland", 391, 526592, 4462),
          new R("Schottland", 315, 526592, 110),
          new R("Wales", 497, 0, 0),
          new R("Nordirland", 508, 526336, 4128)
        ]),
        new this("Malta", 30024, 534528, 33624428, [
          new R("Malta", 206, 534528, 33624428)
        ]),
        new this("Osteuropa", 30025, 4073984, 1174478702, [
          new R("Sankt Petersburg & Umgebung", 499, 2560, 106),
          new R("Riga", 297, 526336, 4200),
          new R("Georgien", 534, 0, 0),
          new R("Weißrussland", 533, 524288, 32),
          new R("Moskau & Umgebung", 225, 526336, 40),
          new R("Rumänien", 301, 526336, 4100),
          new R("Ukraine & Krim", 176, 2048, 4388),
          new R("Russland - sonstige Angebote", 513, 2048, 4192),
          new R("Russische Riviera", 501, 2048, 4096),
          new R("Litauen", 377, 526336, 104),
          new R("Bulgarien (Goldstrand)", 103, 3016704, 1174413156),
          new R("Bulgarien (Sonnenstrand)", 333, 3803136, 1140921190),
          new R("Bulgarien (Landesinnere)", 183, 2048, 40),
          new R("Serbien, Montenegro", 223, 665600, 4164),
          new R("Estland", 348, 526336, 104),
          new R("Bukarest & Umgebung", 502, 526336, 40)
        ]),
        new this("Zypern", 30026, 993536, 1451299175, [
          new R("Republik Zypern (Süden)", 390, 993536, 1451299175)
        ]),
        new this("Karibik", 30027, 2771200, 1199640934, [
          new R("Kuba - Varadero & Havanna", 373, 674048, 109121830),
          new R("Dom. Republik - Süden (Santo Domingo)", 75, 674048, 4390),
          new R("Dom. Republik - Norden (Puerto Plata & Samana)", 400, 149760,
                1132532038),
          new R("Dom. Republik - Osten (Punta Cana)", 401, 674048, 25235782),
          new R("Harbour Island", 475, 16384, 4096),
          new R("St. Marteen (nl.) & St.Eustatius & Saba", 754, 16384, 4096),
          new R("Tobago", 363, 18688, 8392768),
          new R("Kuba (Holguin)", 118, 673792, 1098912068),
          new R("Virgin Islands & Anguilla", 378, 18688, 4166),
          new R("Jamaika", 153, 674048, 33624390),
          new R("St. Martin (frz.)", 741, 18432, 4164),
          new R("Barbados", 31, 542976, 4166),
          new R("Caracas", 51, 16384, 0),
          new R("Antigua & Barbuda", 18, 542976, 4166),
          new R("St. Vincent & Grenadinen", 49, 18688, 6),
          new R("Guadeloupe", 109, 542976, 4164),
          new R("Bahamas", 27, 542976, 69958),
          new R("Curacao & Aruba & Bonaire", 240, 542976, 42013030),
          new R("Grenada", 108, 542976, 4166),
          new R("St.Lucia", 337, 18688, 8392774),
          new R("Puerto Rico", 284, 542976, 4132),
          new R("Isla Margarita", 148, 2115840, 4420),
          new R("Turks & Caicos Inseln", 368, 18432, 4102),
          new R("Martinique", 209, 542976, 4166)
        ]),
        new this("Neuseeland", 30028, 543232, 4203, [
          new R("Süd-Insel (Neuseeland)", 341, 18944, 4193),
          new R("Nord-Insel (Neuseeland)", 247, 543232, 107)
        ]),
        new this("Aegypten", 30029, 4008192, 1871876462, [
          new R("Marsa Matruh & Alexandria", 791, 10240, 4096),
          new R("Sharm el Sheikh / Nuweiba / Taba", 327, 2623744, 1838158150),
          new R("Marsa Alam & Quseir", 287, 1116160, 1720717636),
          new R("Luxor & Assuan", 198, 2099200, 1048684),
          new R("Hurghada & Safaga", 121, 1902848, 1871876452),
          new R("Kairo & Gizeh & Memphis", 158, 10496, 1052782)
        ]),
        new this("Südsee", 30030, 18432, 4166, [
          new R("Polynesien", 279, 18432, 4166),
          new R("Huahine", 461, 16384, 4160),
          new R("Raiatea", 478, 16384, 4096),
          new R("Tahiti", 511, 18432, 4162),
          new R("Moorea", 468, 18432, 4162),
          new R("Cook Inseln", 509, 18432, 4160),
          new R("Fidschi-Inseln", 516, 18432, 4164),
          new R("Tonga-Inseln", 494, 16384, 0),
          new R("Upolu & Savaii", 458, 16384, 64),
          new R("Tuamoto-Inseln", 472, 16384, 4160)
        ]),
        new this("Island", 30031, 524544, 110, [
          new R("Island", 149, 524544, 110)
        ]),
        new this("Südafrika", 30032, 542976, 4207, [
          new R("Krüger Park", 517, 542976, 65),
          new R("Durban & Umgebung", 77, 542976, 4173),
          new R("Eastern Cape", 753, 18688, 4160),
          new R("Johannesburg & Umgebung", 156, 542720, 75),
          new R("Free State", 500, 16384, 0),
          new R("Northern Cape", 504, 16384, 64),
          new R("Swasiland", 346, 18432, 4),
          new R("Northern Province", 493, 18432, 4161),
          new R("Kapstadt & Umgebung", 163, 542976, 4207),
          new R("Nordwesten", 495, 18432, 68)
        ]),
        new this("Indischer Ozean", 30033, 18688, 1182938471, [
          new R("Sri Lanka", 334, 18432, 41956677),
          new R("Seychellen", 322, 18688, 41947494),
          new R("Malediven", 204, 18432, 1115820358),
          new R("Réunion", 291, 18432, 8392773),
          new R("Mauritius", 210, 18688, 1149243462)
        ]),
        new this("Kreuzfahrten", 30034, 28672, 0, [
          new R("Nilkreuzfahrten", 539, 0, 0),
          new R("Schiffsreise Schweden", 639, 0, 0),
          new R("Kreuzfahrt Türkei", 544, 8192, 0),
          new R("Kreuzfahrt Region Donau", 609, 0, 0),
          new R("weitere Kreuzfahrten", 524, 24576, 0),
          new R("Kreuzfahrt Region Nordsee - Ostsee", 671, 4096, 0),
          new R("Flußkreuzfahrt Deutschland", 771, 0, 0),
          new R("Kreuzfahrt Region Mittelmeer", 669, 8192, 0),
          new R("Kreuzfahrten Mallorca", 764, 8192, 0)
        ]),
        new this("Afrika", 30035, 4155648, 1333999471, [
          new R("Namibia", 229, 542976, 4171),
          new R("Kap Verde - Santiago", 309, 0, 4096),
          new R("Kenia - Nairobi", 512, 16384, 32),
          new R("Mozambique", 520, 18432, 4096),
          new R("Kap Verde - Sal", 305, 2048, 69956),
          new R("Senegal", 321, 0, 0),
          new R("Simbabwe", 325, 16640, 64),
          new R("Kap Verde - Sao Vicente & Santa Luzia", 444, 0, 4192),
          new R("Kap Verde - Santo Antao", 445, 0, 4161),
          new R("Kap Verde - Boavista", 40, 133120, 69892),
          new R("Tansania - Sansibar", 349, 18432, 4420),
          new R("Tunesien - Hammamet", 115, 2828544, 1333867876),
          new R("Marokko - Inland", 127, 2048, 35),
          new R("Tunesien - Oase Tozeur", 253, 131072, 0),
          new R("Marokko - Marrakesch", 208, 526592, 42140014),
          new R("Tunesien - Oase Zarzis", 254, 141312, 4356),
          new R("Marokko - Norden", 404, 133376, 4204),
          new R("Tunesien - Insel Djerba", 133, 4139264, 1333868388),
          new R("Marokko - Agadir", 6, 2230528, 1149440292),
          new R("Tunesien - Norden", 246, 600064, 4364),
          new R("Tunesien - Monastir", 221, 3811584, 1149318980),
          new R("Tunesien - Inland", 129, 0, 0),
          new R("Sambia", 735, 16384, 0),
          new R("Kap Verde - Fogo & Brava", 446, 0, 64),
          new R("Botswana", 42, 16384, 0),
          new R("Westafrika & Inseln", 749, 0, 0),
          new R("Kap Verde - Sao Nicolau", 447, 0, 0),
          new R("Kenia - Nordküste", 248, 83968, 4422),
          new R("Gambia", 99, 524544, 4096),
          new R("Kenia - Südküste", 342, 2705664, 4420),
          new R("Kap Verde - Maio", 448, 0, 0)
        ]),
        new this("Südamerika", 30036, 674048, 33558894, [
          new R("Uruguay", 598, 16384, 4098),
          new R("Venezuela: Küste & Inland", 179, 16384, 0),
          new R("Ecuador", 469, 18432, 4168),
          new R("Peru", 470, 18432, 4392),
          new R("Chile", 484, 18432, 4200),
          new R("Brasilien: Recife", 289, 16384, 33558596),
          new R("Brasilien", 660, 674048, 4460),
          new R("Argentinien", 443, 18432, 8),
          new R("Bolivien", 471, 16384, 32),
          new R("Kolumbien", 665, 18432, 4132),
          new R("Brasilien: Rio de Janeiro & Umgebung", 298, 18432, 4104)
        ]),
        new this("Asien", 30037, 542976, 1115690351, [
          new R("Taipeh & Umgebung", 480, 18432, 40),
          new R("China", 55, 18432, 4206),
          new R("Indonesien", 687, 16384, 4160),
          new R("Norden (Chiang Mai, Chiang Rai, Sukhothai)", 778, 18432, 97),
          new R("Tokio, Osaka, Hiroshima, Japan. Inseln", 364, 18432, 10),
          new R("Hongkong & Umgebung", 119, 18432, 98),
          new R("Philippinen: Region Cebu & Borocay", 488, 18432, 4164),
          new R("Vietnam", 376, 18688, 4206),
          new R("Myanmar", 227, 18432, 4196),
          new R("Philippinen", 274, 18432, 4160),
          new R("Usbekistan", 496, 16384, 0),
          new R("Laos", 529, 16384, 32),
          new R("Indien: Region Neu Delhi & Bombay", 479, 18432, 108),
          new R("Indonesien: Insel Bintan", 131, 16384, 4160),
          new R("Singapur", 328, 542976, 42),
          new R("Südkorea", 481, 16384, 40),
          new R("Südosten (Pattaya, Jomtien)", 781, 542720, 4454),
          new R("Westen (Hua Hin, Cha Am, River Kwai)", 780, 18688, 8393028),
          new R("Nordosten (Issan)", 779, 16384, 64),
          new R("Süden (Surat Thani, Trang)", 782, 18432, 4420),
          new R("Insel Ko Samui", 136, 18688, 41947494),
          new R("Khao Lak & Umgebung", 169, 542976, 4164),
          new R("Inseln im Golf von Thailand (Koh Chang, Koh Phangan)", 356,
                18432, 4162),
          new R("Inseln in der Andaman See (Koh Pee Pee, Koh Lanta)", 355,
                18432, 4164),
          new R("Krabi & Umgebung", 783, 18432, 8392774),
          new R("sonstige Angebote Thailand", 437, 16384, 0),
          new R("Bangkok & Umgebung", 30, 542720, 106),
          new R("Insel Phuket", 142, 18688, 1115689318),
          new R("Indien", 679, 18432, 4164),
          new R("Indonesien: Java", 477, 542976, 44),
          new R("Brunei-Darussalam", 47, 18432, 0),
          new R("Philippinen: Luzon & Manila", 487, 18432, 40),
          new R("Indonesien: Sunda-Inseln", 345, 18432, 4161),
          new R("Nepal", 232, 16384, 64),
          new R("Macau", 200, 18432, 0),
          new R("Malaysia", 203, 18688, 4206),
          new R("Indonesien: Bali", 29, 18688, 41948519),
          new R("Kambodscha", 162, 18432, 4196),
          new R("Indien: Goa", 102, 18432, 4422)
        ]),
        new this("Griechenland", 30038, 3877120, 1602656111, [
          new R("Thassos", 357, 534528, 67113061),
          new R("Andros", 16, 8192, 0),
          new R("Korfu", 172, 3876864, 126128484),
          new R("weitere Angebote Griechische Inseln", 415, 534528, 64),
          new R("Kos", 174, 731136, 1602621764),
          new R("Epiros", 87, 534528, 4192),
          new R("Zakynthos", 387, 141312, 33558596),
          new R("Kreta", 175, 3877120, 1468438375),
          new R("Ikaria", 124, 8192, 4096),
          new R("Aegina", 5, 8192, 64),
          new R("Lefkas & Meganissi", 187, 10240, 4164),
          new R("Samos", 308, 534528, 100667460),
          new R("Leros", 188, 8192, 68),
          new R("Rhodos", 295, 3877120, 1468305766),
          new R("Chios", 56, 8192, 4160),
          new R("Santorin", 310, 10240, 33558630),
          new R("Syros", 329, 8192, 4096),
          new R("Kefalonia", 167, 10240, 4164),
          new R("Skiathos & Skopelos", 331, 534528, 4164),
          new R("Amorgos", 15, 8192, 0),
          new R("Alonissos", 14, 8192, 64),
          new R("Ios", 145, 8192, 64),
          new R("Symi", 347, 8192, 4192),
          new R("Euböa (Evia)", 672, 8192, 4420),
          new R("Poros", 280, 8192, 4162),
          new R("Karpathos", 164, 8192, 4160),
          new R("Lesbos", 189, 532480, 4164),
          new R("Mykonos", 228, 10240, 33820742),
          new R("Kalymnos", 161, 8192, 64),
          new R("Tilos", 361, 8192, 0),
          new R("Patmos", 270, 8192, 0),
          new R("Hydra, Spetses", 122, 8192, 0),
          new R("Paros, Serifos & Sifnos", 269, 532480, 4162),
          new R("Tinos", 362, 8192, 64),
          new R("Naxos", 230, 10240, 33558596),
          new R("Thessaloniki", 358, 10240, 4138),
          new R("Olympische Riviera", 673, 10240, 4356),
          new R("Athen & Umgebung", 23, 534528, 266351),
          new R("Pilion", 113, 8192, 4192),
          new R("Chalkidiki", 54, 1583360, 1174671684),
          new R("Peloponnes", 271, 534784, 1199837511),
          new R("Thessalien", 747, 8192, 64),
          new R("Thrakien", 674, 8192, 0),
          new R("Makedonien", 748, 532480, 4160),
          new R("Folegandros", 92, 8192, 64)
        ]),
        new this("Mittelamerika", 30039, 674560, 1107366255, [
          new R("Panama", 267, 18432, 4164),
          new R("Costa Rica", 67, 18688, 69734),
          new R("Mexiko Stadt & Umgebung", 216, 16384, 104),
          new R("Mexiko", 215, 18688, 69959),
          new R("Acapulco / Oaxaca", 2, 18432, 4132),
          new R("Yucatan / Cancun", 386, 674048, 1107366246),
          new R("Guatemala", 110, 16384, 64),
          new R("Inland", 490, 16896, 96)
        ]),
        new this("Deutschland Specials", 30040, 4096, 0, [
          new R("Radtouren und andere Specials", 439, 4096, 0),
          new R("Deutschland - sonstige Angebote", 655, 0, 0)
        ]),
        new this("Glückshotels", 30043, 28672, 0, [
          new R("Glückshotel Kalabrien", 623, 8192, 0),
          new R("Glückshotel Italien", 621, 8192, 0),
          new R("Glückshotel Frankreich", 628, 0, 0),
          new R("Glückshotel Formentera", 559, 0, 0),
          new R("Glückshotel Costa de la Luz", 563, 8192, 0),
          new R("Glückshotel Fuerteventura", 553, 0, 0),
          new R("Glückshotel Marokko", 577, 0, 0),
          new R("Glückshotel Kroatien", 135, 8192, 0),
          new R("Glückshotel Türkische Riviera", 548, 8192, 0),
          new R("Glückshotel USA", 680, 16384, 0),
          new R("Glückshotel Türkei", 546, 8192, 0),
          new R("Glückshotel Gardasee", 290, 0, 0),
          new R("Glückshotel Madeira", 593, 0, 0),
          new R("Glückshotel Portugal", 594, 0, 0),
          new R("Glückshotel Schweiz", 427, 0, 0),
          new R("Glückshotel Dominikanische Republik", 423, 16384, 0),
          new R("Glückshotel Lanzarote", 557, 0, 0),
          new R("Glückshotel Oesterreich", 610, 0, 0),
          new R("Glückshotel Kuba", 419, 16384, 0),
          new R("Glückshotel Deutschland", 638, 4096, 0),
          new R("Glückshotel Sardinien", 619, 8192, 0),
          new R("Glückshotel Ischia", 625, 8192, 0)
        ]),
        new this("Rundreisen", 30044, 24576, 0, [
          new R("Rundreise Aegypten", 540, 8192, 0),
          new R("Rundreise Arabische Halbinsel", 430, 0, 0),
          new R("Rundreise Südamerika", 433, 16384, 0),
          new R("Rundreise Naher Osten", 740, 8192, 0),
          new R("Rundreise Afrika", 739, 16384, 0),
          new R("Rundreise Zypern", 429, 8192, 0),
          new R("Rundreise Brasilien", 523, 16384, 0),
          new R("Rundreise Venezuela", 522, 16384, 0),
          new R("Rundreise Griechenland", 612, 8192, 0),
          new R("Rundreise Indien", 590, 16384, 0),
          new R("Rundreise Tunesien", 542, 8192, 0),
          new R("Rundreise Frankreich", 627, 8192, 0),
          new R("Rundreise Portugal", 412, 0, 0),
          new R("Rundreise Kuba", 413, 16384, 0),
          new R("Rundreise Türkei", 545, 8192, 0),
          new R("Rundreise Andalusien", 564, 8192, 0),
          new R("Rundreise Sri Lanka", 453, 16384, 0),
          new R("Rundreise Kreta", 567, 8192, 0),
          new R("Rundreise Südafrika", 583, 16384, 0),
          new R("Rundreise Kenia", 585, 16384, 0),
          new R("Rundreise Oman", 455, 0, 0),
          new R("Rundreise Tansania", 586, 16384, 0),
          new R("Rundreise Jordanien", 587, 0, 0),
          new R("Rundreise Thailand", 588, 16384, 0),
          new R("Rundreise Spanien", 677, 0, 0),
          new R("Rundreise Madeira", 592, 0, 0),
          new R("Rundreise Azoren", 595, 0, 0),
          new R("Rundreise Japan", 596, 16384, 0),
          new R("Rundreise Vietnam", 597, 16384, 0),
          new R("Rundreise Kanada", 599, 16384, 0),
          new R("Rundreise Jamaika", 424, 16384, 0),
          new R("Rundreise Russland", 600, 0, 0),
          new R("Rundreise China", 601, 16384, 0),
          new R("Rundreise Ecuador", 668, 16384, 0),
          new R("Rundreise Asien", 602, 16384, 0),
          new R("Rundreise Island", 326, 0, 0),
          new R("Rundreise La Reunion", 421, 16384, 0),
          new R("Rundreise Skandinavien", 663, 0, 0),
          new R("Rundreise Australien & Neuseeland", 608, 16384, 0),
          new R("Rundreise Baltikum", 658, 0, 0),
          new R("Rundreise Kroatien", 482, 8192, 0),
          new R("Rundreise Sizilien", 615, 8192, 0),
          new R("Rundreise Zakynthos", 649, 8192, 0),
          new R("Rundreise Malaysia", 646, 16384, 0),
          new R("Rundreise Namibia", 644, 16384, 0),
          new R("Rundreise Marokko", 642, 0, 0),
          new R("Rundreise Costa Rica", 641, 16384, 0),
          new R("Rundreise Indonesien", 418, 16384, 0),
          new R("Rundreise Sardinien", 617, 8192, 0),
          new R("Rundreise Italien", 618, 8192, 0),
          new R("Rundreise Peru - Südamerika", 636, 16384, 0),
          new R("Rundreise Polen", 633, 0, 0),
          new R("Rundreise Mexiko", 629, 16384, 0)
        ]),
        new this("Naher Osten", 30045, 534784, 4462, [
          new R("Katar", 166, 2304, 4128),
          new R("Bahrain", 28, 2304, 4098),
          new R("Oman", 258, 526592, 4198),
          new R("Eilat", 80, 2048, 4100),
          new R("Libanon", 191, 10240, 4450),
          new R("Tel Aviv & Umgebung", 350, 10240, 4140),
          new R("Jordanien", 157, 526336, 4166),
          new R("Jerusalem & Umgebung", 155, 10240, 76),
          new R("Israel", 682, 10240, 4100),
          new R("Totes Meer", 366, 10240, 4100)
        ]),
        new this("Fly & Stay", 30046, 16384, 0, [
          new R("Fly & Stay Asien", 785, 16384, 0)
        ])
      ];
    }
  }
});

SearchMask.Duration = new JS.Class(SearchMask.FinderLogic, {
  initialize: function(name, duration_id, earth, lastminute, min_nights,
                       max_nights) {
    this.name = name;
    this.duration_id = duration_id;
    this.earth = earth;
    this.lastminute = lastminute;
    this.min_nights = min_nights;
    this.max_nights = typeof(max_nights) === 'undefined' ?
                     min_nights : max_nights;
  },
  to_url_params: function() {
    return this.duration_id == this.klass.default_entry().duration_id ?
           {} : { dauer: this.duration_id };
  },
  limit: function(nights, form) {
    var self = this;
    var largest_possible_option = null;
    var largest_possible_min_nights = null;
    $(this.klass.element_selector + " option", form).each(function(i, element) {
      var duration = self.klass.find_by_id(element.value);
      if(duration.min_nights > nights) {
        element.setAttribute('disabled', 'disabled');
      } else {
        element.removeAttribute('disabled');
        largest_possible_option = element;
        largest_possible_min_nights = duration.min_nights;
      }
    });

    $.fix_ie_disabled_options();

    if(this.min_nights > largest_possible_min_nights) {
      largest_possible_option.selected = true;
    }
  },
  get_value: function(){
     return this.duration_id;
  },
  extend: {
    fetch_all: function() {
      return [
        new this('beliebig', '-1', true, true, 0, 1000),
        new this('1 Tag', '6_1', true, false, 1),
        new this('2 Tage', '6_2', true, false, 2),
        new this('3 Tage', '6_3', true, false, 3),
        new this('4 Tage', '6_4', true, false, 4),
        new this('5 Tage', '6_5', true, false, 5),
        new this('6 Tage', '6_6', true, false, 6),
        new this('7 Tage', '6_7', true, false, 7),
        new this('8 Tage', '6_8', true, false, 8),
        new this('9 Tage', '6_9' , true, false, 9),
        new this('10 Tage', '6_10', true, false, 10),
        new this('11 Tage', '6_11', true, false, 11),
        new this('12 Tage', '6_12', true, false, 12),
        new this('13 Tage', '6_13', true, false, 13),
        new this('14 Tage', '6_14', true, false, 14),
        new this('15 Tage', '6_15', true, false, 15),
        new this('16 Tage' ,'6_16', true, false, 16),
        new this('17 Tage', '6_17', true, false, 17),
        new this('18 Tage', '6_18', true, false, 18),
        new this('19 Tage', '6_19', true, false, 19),
        new this('20 Tage', '6_20', true, false, 20),
        new this('21 Tage', '6_21', true, false, 21),
        new this('1-4 Tage', '9', false, true, 1, 4),
        new this('5-8 Tage', '10', false, true, 5, 8),
        new this('1 Woche', '6_7', false, true, 7),
        new this('9-12 Tage', '7', false, true, 9, 12),
        new this('13-15 Tage', '3', false, true, 13, 15),
        new this('2 Wochen', '6_14', false, true, 14),
        new this('16-22 Tage', '12', false, true, 16, 22),
        new this('3 Wochen', '6_21', false, true, 21),
        new this('>22 Tage', '13', true, true, 23, 1000)
      ];
    },
    element_selector: '#duration_id',
    underscore_class_name: 'duration',
    tt_key: 'dauer'
  }
});

SearchMask.FormState = new JS.Class({
  initialize: function(form_element) {
    this.form_element = form_element;
  },
  get: function() {
    var self = this;
    this.for_every_field(function(clazz) {
      this.set_obj(clazz.find_by_form(this.form_element, self));
    });
  },
  get_one: function(clazz) {
    var self = this;
    this.set_obj(clazz.find_by_form(this.form_element, self));
  },
  put: function() {
    this.for_every_field(function(clazz) {
      this[clazz.underscore_class_name].put_to_form(this.form_element);
    });
  },
  put_one: function(clazz) {
      this[clazz.underscore_class_name].put_to_form(this.form_element);
  },
  to_url: function() {
    this.klass.get_cookie_obj().put(this);
    var url_params = {
      KID: SearchMask.Settings.tt_kid,
      showresult: 1,
      formular: 4,
      agent: SearchMask.affiliate.agent,
      subagent1: SearchMask.affiliate.subagent1,
      subagent2: SearchMask.affiliate.subagent2
    };
    $.extend(url_params, this.klass.extra_url_params());

    this.for_every_field(function(clazz) {
      if (this[clazz.underscore_class_name] === null) {
        return;
      }
      var p = this[clazz.underscore_class_name].to_url_params();
      $.extend(url_params, p);
    });
    return this.klass.tt_booking_url() + '?' + $.param(url_params);
  },
  set_from_defaults: function() {
    this.for_every_field(function(clazz) {
      this.set_obj(clazz.default_entry());
    });
  },
  set_from_url_and_cookie_and_start_params: function() {
    var converter = new SearchMask.ParamsConverter();
    var cookie = this.klass.get_cookie_obj();
    var c_p = converter.from_hash(cookie.to_hash()).to_hash();
    converter = new SearchMask.ParamsConverter();
    var s_p = converter.from_hash(SearchMask.start_params).to_hash();
    converter = new SearchMask.ParamsConverter();
    var u_p = converter.from_url().to_hash();
    var params = $.extend(c_p, u_p, s_p);
    this.for_every_field(function(clazz) {
      this.set_obj(clazz.from_url_params(params));
    });
  },
  for_every_field: function(func) {
    var classes = this.klass.get_field_classes();
    for(var i = 0; i < classes.length; i++) {
      func.call(this, classes[i]);
    }
  },
  validate_travelers: function() {
    this.travelers.validate(this.form_element, this);
  },
  validate_date_range: function() {
    this.date_range.validate(this);
  },
  set_obj: function(obj) {
    obj.form_state = this;
    this[obj.klass.underscore_class_name] = obj;
  },
  extend: {
    get_cookie_obj: function() {
      return new SearchMask.Cookie(this.get_cookie_prefix());
    }
  }
});
SearchMask.LastminuteFormState = new JS.Class(SearchMask.FormState, {
  initialize: function(form_element) {
    this.callSuper(form_element);
    this.destination_autocompleter =
      new SelectAutocompleter(SearchMask.Destination.element_selector,
                              SearchMask.Destination.find_all_countries());
  },
  extend: {
    tt_booking_url: function() {
      return SearchMask.Settings.tt_booking_url;
    },
    extra_url_params: function() {
      return {};
    },
    get_cookie_prefix: function() {
      return 'LM';
    },
    get_field_classes: function() {
      return [
        SearchMask.DepartureAirport,
        SearchMask.Destination,
        SearchMask.Operator,
        SearchMask.DateRange,
        SearchMask.Duration,
        SearchMask.Travelers,
        SearchMask.Category,
        SearchMask.HotelName,
        SearchMask.FamilyChildren,
        SearchMask.Beach,
        SearchMask.Wellness,
        SearchMask.Seaview,
        SearchMask.Club,
        SearchMask.Price,
        SearchMask.AccomodationType,
        SearchMask.Catering,
        SearchMask.Sport
      ];
    }
  }
});
SearchMask.EarthFormState = new JS.Class(SearchMask.FormState, {
  initialize: function(form_element) {
    this.callSuper(form_element);
    this.setup_autocompleter();
  },
  setup_autocompleter: function(countries) {
    if (countries === undefined) {
      countries = SearchMask.DestinationEarth.find_all_countries();
    }
    this.destination_autocompleter =
      new SelectAutocompleter(SearchMask.DestinationEarth.element_selector,
                              countries);
    this.destination_autocompleter.unset();
  },
  extend: {
    tt_booking_url: function() {
      return SearchMask.Settings.tt_booking_earth_url;
    },
    extra_url_params: function() {
      return { engine: 'erde' };
    },
    get_cookie_prefix: function() {
      return 'H';
    },
    get_field_classes: function() {
      return [
        SearchMask.Theme,
        SearchMask.DestinationEarth,
        SearchMask.Operator,
        SearchMask.DateRange,
        SearchMask.Duration,
        SearchMask.Travelers,
        SearchMask.Category,
        SearchMask.HotelName,
        SearchMask.Price,
        SearchMask.AccomodationType,
        SearchMask.Catering
      ];
    }
  }
});
SearchMask.SimpleValue = new JS.Class({

  initialize: function(value) {
    this.value = value;
  },
  put_to_form: function(form) {
    $(this.klass.element_selector, form).val(this.value);
  },
  get_value: function(){
    return this.value;
  },
  extend: {
    find_by_form: function(form) {
      return new this($(this.element_selector, form).val());
    },
    default_entry: function() {
      return new this('');
    }
  }
});

SearchMask.HotelName = new JS.Class(SearchMask.SimpleValue, {

  to_url_params: function() {
    return this.value.length > 0 ? { shotel: this.value } : {};
  },
  extend: {
    from_url_params: function(params) {
      if($.is_defined(params, "hotel_name")) {
        return new this(params.hotel_name);
      } else {
        return this.default_entry();
      }
    },
    element_selector: '#hotel_name',
    underscore_class_name: 'hotel_name'
  }
});

SearchMask.OfficialHoliday = new JS.Class(SearchMask.FinderLogic, {
  initialize: function(name, datums, state_ids, uniform, comments) {
    this.name = name;
    this.datums = datums;
    this.comments = comments;
    this.state_ids = state_ids;
    this.uniform = uniform;
  },
  describe: function() {
    var rt = this.name;
    if ($.is_defined(this, "comments")) {
      rt += " (" + this.comments + ")";
    }
    return rt;
  },
  css_class_name: "official_holiday",
  extend: {
    find_by_state: function(state) {
      return $.find_all(
        this.find_all(), function(holiday) {
          if (holiday.state_ids.toString().indexOf(state) > -1) {
            return holiday;
          }
          else {
            return null;
          }
        });
    },
    find_uniform: function() {
      return $.find_all(
        this.find_all(), function(holiday) {
          if (holiday.uniform === true) {
            return holiday;
          }
          else {
            return null;
          }
        });
    },
    datums_by_day_and_month: function(day, month) {
      return [ new Date(2010, month-1, day), new Date(2011, month-1, day),
               new Date(2012, month-1, day), new Date(2013, month-1, day),
               new Date(2014, month-1, day), new Date(2015, month-1, day) ];
    },
    fetch_all: function() {
      var all_de = SearchMask.State.all_state_ids("DE");
      var all_ch = SearchMask.State.all_state_ids("CH");
      var all_at = SearchMask.State.all_state_ids("AT");
      function d(y, m, day) {return new Date(y, m-1, day);}

      return [
        new this('Neujahrstag',
                 this.datums_by_day_and_month(1, 1),
                 $.merge(all_de, all_ch, all_at),
                 true
        ),
        new this('Hl. Drei Könige',
                 this.datums_by_day_and_month(6, 1),
                 $.merge(['BW', 'BY', 'ST'], all_at),
                 false
        ),
        new this('Karfreitag',
          [ d(2010, 4, 2), d(2011, 4, 22),
            d(2012, 4, 6), d(2013, 3, 29),
            d(2014, 4, 18), d(2015, 4, 3) ],
          $.merge(all_de, all_at),
          true
        ),
        new this('Ostermontag',
          [ d(2010, 4, 5), d(2011, 4, 25),
            d(2012, 4, 9), d(2013, 4, 1),
            d(2014, 4, 21), d(2015, 4, 6) ],
          $.merge(all_de, all_at),
          true
        ),
        new this('1. Mai',
                 this.datums_by_day_and_month(1, 5),
                 all_de,
                 true),
        new this('Christi Himmelfahrt',
          [ d(2010, 5, 13), d(2011, 6, 2),
            d(2012, 5, 17), d(2013, 5, 12),
            d(2014, 5, 29), d(2015, 5, 14) ],
          $.merge(all_de, all_at),
          true
        ),
        new this('Pfingstmontag',
          [ d(2010, 5, 24), d(2011, 6, 13),
            d(2012, 5, 28), d(2013, 5, 20),
            d(2014, 6, 9), d(2015, 5, 25) ],
          $.merge(all_de, all_at),
          true
        ),
        new this('Fronleichnam',
          [ d(2010, 6, 3), d(2011, 6, 23),
            d(2012, 6, 7), d(2013, 5, 30),
            d(2014, 6, 19), d(2015, 6, 4) ],
          $.merge(['BW', 'BY', 'HE', 'NW', 'RP', 'SL', 'SN', 'TH'], all_at),
          false,
          'nicht in allen Teilen Sachsens und Thüringens'
        ),
        new this('Mariä Himmelfahrt',
                 this.datums_by_day_and_month(15, 8),
                 $.merge(['BY', 'SL'], all_at),
                 false,
          'in bayrischen Gemeinden mit überwiegend katholischer Bevölkerung'
        ),
        new this('Tag der dt. Einheit',
                 this.datums_by_day_and_month(3, 10),
                 all_de,
                 true
        ),
        new this('Reformationstag',
                 this.datums_by_day_and_month(31, 10),
                 ['BB', 'MV', 'SN', 'ST', 'TH'],
                 false
        ),
        new this('Allerheiligen',
                 this.datums_by_day_and_month(1, 11),
                 $.merge(['BW', 'BY', 'NW', 'RP', 'SL'], all_at),
                 false
        ),
        new this('Buß- und Bettag',
          [ d(2010, 11, 17), d(2011, 11, 16),
            d(2012, 11, 21), d(2013, 11, 20),
            d(2014, 11, 19), d(2015, 11, 18) ],
          ['SN'],
          false
        ),
        new this('Auffahrt',
          [ d(2010, 5, 13), d(2011, 6, 2),
            d(2012, 5, 17), d(2013, 5, 9),
            d(2014, 5, 29), d(2015, 5, 14) ],
          all_ch,
          false
        ),
        new this('Bundesfeier',
                 this.datums_by_day_and_month(1, 8),
                 all_ch,
                 false
        ),
        new this('Staatsfeiertag',
                 this.datums_by_day_and_month(1, 5),
                 all_at,
                 false
        ),
        new this('Nationalfeiertag',
                 this.datums_by_day_and_month(26, 10),
                 all_at,
                 false
        ),
        new this('Maria Empfängnis',
                 this.datums_by_day_and_month(8, 12),
                 all_at,
                 false
        ),
        new this('Hl. Abend',
                 this.datums_by_day_and_month(24, 12),
                 all_at,
                 false
        ),
        new this('Christtag',
                 this.datums_by_day_and_month(25, 12),
                 all_at,
                 false
        ),
        new this('Stefanstag',
                 this.datums_by_day_and_month(26, 12),
                 all_at,
                 false
        ),
        new this('Silvester',
                 this.datums_by_day_and_month(31, 12),
                 all_at,
                 false
        ),
        new this('1. Weihnachtstag',
                 this.datums_by_day_and_month(25, 12),
                 $.merge(all_de, all_ch),
                 true
        ),
        new this('2. Weihnachtstag',
                 this.datums_by_day_and_month(26, 12),
                 all_de,
                 true
        )
      ];
    }
  }
});


SearchMask.Operator = new JS.Class(SearchMask.FinderLogic, {
  initialize: function(name, operator_id, earth, lastminute) {
    this.name = name;
    this.operator_id = operator_id;
    this.earth = earth;
    this.lastminute = lastminute;
  },
  to_url_params: function() {
    return this.operator_id == this.klass.default_entry().operator_id ?
           {} : { marke: this.operator_id };
  },
  get_value: function() {
    return this.operator_id;
  },
  extend: {
    fetch_all: function() {
      return [
        new this('beliebig', '-1', true, true),
        new this('1-2-FLY', 'FLY', true, true),
        new this('5 vor Flug', '5VF', true, true),
        new this('ADAC Reisen', 'ADAC', true, false),
        new this('Airtours', 'ATI', true, false),
        new this('Aldiana', 'ALD', true, true),
        new this('Alltours', 'ALL', true, true),
        new this('amajo-reisen', 'AMA', true, true),
        new this('Ameropa', 'AME', true, false),
        new this('Attika Reisen', 'ATK', true, true),
        new this('BG Tours', 'BGT', true, true),
        new this('BigXtra Touristik', 'BIG', true, true),
        new this('Bucher Reisen', 'BU', true, true),
        new this('Club Blaues Meer', 'CBM', true, true),
        new this('Demed', 'DEM', false, true),
        new this('DERTOUR', 'DER', true, true),
        new this('DERTOUR XDER', 'XDER', false, true),
        new this('Discount Travel', 'DIS', false, true),
        new this('Ecco Reisen', 'ECC', true, true),
        new this('Express Travel International', 'ETI', false, true),
        new this('FEFA Reisen', 'FEFA', false, true),
        new this('FERIEN', 'FER', true, true),
        new this('FTI Packaging', 'XFTI', false, true),
        new this('FTI Touristik', 'FTI', true, true ),
        new this('FTS-Travel', 'FTS', false, true),
        new this('Glauch Reisen SUN', 'XGLA', false, true),
        new this('GoBucher', 'XBU', false, true),
        new this('GTI Travel', 'GTI', true, true),
        new this('GTI XGTI', 'XGTI', false, true),
        new this('ITS', 'ITS', true, true),
        new this('Jahn Reisen', 'JAHN', true, true),
        new this('JT Touristik', 'JT', true, true),
        new this('LMX Live', 'XLMX', true, true),
        new this('Malta Direkt Reisen', 'MLA', false, true),
        new this('Medina Reisen', 'MED', true, true),
        new this('Meier\'s Weltreisen', 'MWR', true, true),
        new this('Mondial', 'MON', true, false),
        new this('Neckermann Reisen', 'NEC', true, true),
        new this('Neckermann XNEC', 'XNEC', false, true),
        new this('Nix-wie-weg®.de', 'VTO', true, true),
        new this('Öger Tours', 'OGER', true, true),
        new this('OLIMAR Reisen', 'OLI', true, true),
        new this('Phoenix Reisen', 'PHX', true, true),
        new this('Schauinsland Reisen', 'SLR', true, true),
        new this('Thomas Cook', 'TOC', true, true),
        new this('Thomas Cook XTOC', 'XTOC', false, true),
        new this('Tischler Reisen', 'TISC', true, true),
        new this('Tjaereborg', 'TJAE', true, true),
        new this('TJAEREBORG INDI', 'XTJA', false, true),
        new this('TUI', 'TUI', true, true),
        new this('Urlaubstours', 'ULT', true, true),
        new this('W-Travel', 'WTA', false, true)
      ];
    },
    element_selector: '#operator_id',
    underscore_class_name: 'operator',
    tt_key: 'marke'
  }
});

SearchMask.Price = new JS.Class(SearchMask.SimpleValue, {

  to_url_params: function() {
    return this.value > 0 ? { preis: this.value } : {};
  },
  extend: {
    from_url_params: function(params) {
      if(typeof(params.price) !== 'undefined') {
        return new this(params.price);
      } else {
        return this.default_entry();
      }
    },
    element_selector: '#price',
    underscore_class_name: 'price'
  }
});

SearchMask.SchoolHoliday = new JS.Class(SearchMask.FinderLogic, {
  initialize: function(year, name, state_datums) {
    this.year = year;
    this.name = name;
    var st = {};

    $.each(state_datums, function(key, value) {
      var obj = null;

      obj = [];
      for(var i = 0; i < value.length; i += 6) {
        var x = {
          from: new Date(value[i+0], value[i+1]-1, value[i+2]),
          to: new Date(value[i+3], value[i+4]-1, value[i+5])
        };
        obj.push(x);
      }
      st[key] = obj;
    });
    this.state_datums = st;
  },
  describe: function() {
    return this.name;
  },
  css_class_name: "school_holiday",
  extend: {
    find_by_state: function(state) {
      return $.find_all(this.find_all(), function(holiday) {
        if (typeof(holiday.state_datums[state]) === "object" ) {
          return holiday;
        }
        else {
          return null;
        }
      });
    },
    fetch_all: function() {
      var o_at_10 = [2010, 3, 27, 2010, 4, 6];
      var o_at_11 = [2011, 4, 16, 2011, 4, 26];
      var p_at_10 = [2010, 5, 22, 2010, 5, 25];
      var p_at_11 = [2011, 6, 11, 2011, 6, 14];
      var w_at_10 = [2010, 12, 24, 2010, 1, 6];
      var w_at_11 = [2011, 12, 24, 2012, 1, 6];
      return [
         new this(2010, 'Sportferien', {
          AI: [ 2010, 2, 12, 2010, 2, 21 ],
          BL: [ 2010, 2, 13, 2010, 2, 28 ],
          BS: [ 2010, 2, 13, 2010, 2, 27 ],
          BR: [ 2010, 2, 13, 2010, 2, 21 ],
          FR: [ 2010, 2, 15, 2010, 2, 19 ],
          GE: [ 2010, 2, 20, 2010, 2, 28 ],
          GL: [ 2010, 1, 30, 2010, 2, 7 ],
          GR: [ 2010, 2, 20, 2010, 2, 28 ],
          JU: [ 2010, 2, 13, 2010, 2, 21 ],
          LU: [ 2010, 2, 6, 2010, 2, 21 ],
          NE: [ 2010, 2, 27, 2010, 3, 7 ],
          ND: [ 2010, 2, 6, 2010, 2, 21 ],
          OW: [ 2010, 2, 6, 2010, 2, 21 ],
          SF: [ 2010, 1, 30, 2010, 2, 4 ],
          SZ: [ 2010, 2, 27, 2010, 3, 7 ],
          SO: [ 2010, 2, 6, 2010, 2, 21 ],
          TI: [ 2010, 2, 13, 2010, 2, 21 ],
          TG: [ 2010, 1, 30, 2010, 2, 7 ],
          UR: [ 2010, 2, 6, 2010, 2, 16 ],
          VD: [ 2010, 2, 5, 2010, 2, 15 ],
          VS: [ 2010, 2, 5, 2010, 2, 15 ],
          ZG: [ 2010, 2, 6, 2010, 2, 21 ],
          ZH: [ 2010, 2, 13, 2010, 2, 28 ]
        }),
        new this(2010, 'Frühlingsferien', {

          AG: [2010, 4, 12, 2010, 4, 23],
          AR: [2010, 4, 2, 2010, 4, 18],
          AI: [2010, 4, 2, 2010, 4, 18],
          BL: [2010, 4, 1, 2010, 4, 11],
          BS: [2010, 4, 1, 2010, 4, 11],
          BR: [2010, 4, 2, 2010, 4, 18],
          FR: [2010, 3, 29, 2010, 4, 9],
          GE: [2010, 4, 1, 2010, 4, 11],
          GL: [2010, 4, 2, 2010, 4, 18],
          GR: [2010, 4, 17, 2010, 5, 2],
          JU: [2010, 4, 2, 2010, 4, 18],
          LU: [2010, 4, 2, 2010, 4, 18],
          NE: [2010, 4, 2, 2010, 4, 18],
          ND: [2010, 4, 2, 2010, 4, 18],
          OW: [2010, 4, 2, 2010, 4, 18],
          SF: [2010, 4, 17, 2010, 5, 2],
          SZ: [2010, 5, 1, 2010, 5, 16],
          SO: [2010, 4, 2, 2010, 4, 18],
          SG: [2010, 3, 27, 2010, 4, 11],
          TI: [2010, 4, 2, 2010, 4, 11],
          TG: [2010, 4, 2, 2010, 4, 18],
          UR: [2010, 4, 2, 2010, 4, 18],
          VD: [2010, 3, 26, 2010, 4, 12],
          VS: [2010, 3, 31, 2010, 4, 12],
          ZG: [2010, 4, 17, 2010, 5, 2],
          ZH: [2010, 4, 24, 2010, 5, 9]
        }),
        new this(2010, 'Winterferien', {
          BY: [2010, 2, 15, 2010, 2, 20],
          BE: [2010, 2, 1, 2010, 2, 6],
          BB: [2010, 2, 1, 2010, 2, 6],
          HB: [2010, 2, 1, 2010, 2, 6],
          HH: [2010, 1, 29, 2010, 1, 29],
          MV: [2010, 2, 6, 2010, 2, 20],
          NI: [2010, 2, 1, 2010, 2, 2],
          SL: [2010, 2, 15, 2010, 2, 20],
          SN: [2010, 2, 8, 2010, 2, 20],
          ST: [2010, 2, 8, 2010, 2, 13],
          TH: [2010, 2, 1, 2010, 2, 6]

        }),
        new this(2010, 'Semesterferien', {

          BGL: [2010, 2, 8, 2010, 2, 13],
          KTN: [2010, 2, 8, 2010, 2, 13],
          NOE: [2010, 2, 1, 2010, 2, 6],
          OOE: [2010, 2, 15, 2010, 2, 20],
          SBG: [2010, 2, 8, 2010, 2, 13],
          STM: [2010, 2, 15, 2010, 2, 20],
          TIR: [2010, 2, 8, 2010, 2, 13],
          VBG: [2010, 2, 8, 2010, 2, 13],
          W: [2010, 2, 1, 2010, 2, 6]

        }),
        new this(2010, 'Osterferien', {
          BW: [2010, 4, 1, 2010, 4, 10],
          BY: [2010, 3, 29, 2010, 4, 10],
          BE: [2010, 3, 31, 2010, 4, 10],
          BB: [2010, 3, 31, 2010, 4, 10],
          HB: [2010, 3, 19, 2010, 4, 6],
          HH: [2010, 3, 8, 2010, 3, 20],
          HE: [2010, 3, 29, 2010, 4, 10],
          MV: [2010, 3, 29, 2010, 4, 7],
          NI: [2010, 3, 19, 2010, 4, 6],
          NW: [2010, 3, 27, 2010, 4, 10],
          RP: [2010, 3, 26, 2010, 4, 9],
          SL: [2010, 3, 29, 2010, 4, 10],
          SN: [2010, 4, 1, 2010, 4, 10],
          ST: [2010, 3, 29, 2010, 4, 9],
          SH: [2010, 4, 3, 2010, 4, 17],
          TH: [2010, 3, 29, 2010, 4, 9],

          BGL: o_at_10,
          KTN: o_at_10,
          NOE: o_at_10,
          OOE: o_at_10,
          SBG: o_at_10,
          STM: o_at_10,
          TIR: o_at_10,
          VBG: o_at_10,
          W:   o_at_10

        }),
        new this(2010, 'Pfingstferien', {
          BW: [2010, 5, 25, 2010, 6, 5],
          BY: [2010, 5, 25, 2010, 6, 5],
          BE: [2010, 5, 14, 2010, 5, 14, 2010, 5, 25, 2010, 5, 25],
          BB: [2010, 5, 14, 2010, 5, 14],
          HB: [2010, 5, 14, 2010, 5, 14, 2010, 5, 25, 2010, 5, 25],
          HH: [2010, 4, 15, 2010, 5, 22],
          MV: [2010, 5, 21, 2010, 5, 22],
          NI: [2010, 5, 14, 2010, 5, 14, 2010, 5, 25, 2010, 5, 25],
          NW: [2010, 5, 25, 2010, 5, 25],
          SN: [2010, 5, 14, 2010, 5, 14],
          ST: [2010, 5, 14, 2010, 5, 22],

          BGL: p_at_10,
          KTN: p_at_10,
          NOE: p_at_10,
          OOE: p_at_10,
          SBG: p_at_10,
          STM: p_at_10,
          TIR: p_at_10,
          VBG: p_at_10,
          W: p_at_10

        }),
        new this(2010, 'Sommerferien', {
          BW: [2010, 7, 29, 2010, 9, 11],
          BY: [2010, 8, 2, 2010, 9, 13],
          BE: [2010, 7, 7, 2010, 8, 21],
          BB: [2010, 7, 8, 2010, 8, 21],
          HB: [2010, 6, 24, 2010, 8, 4],
          HH: [2010, 7, 8, 2010, 8, 18],
          HE: [2010, 7, 5, 2010, 8, 14],
          MV: [2010, 7, 12, 2010, 8, 21],
          NI: [2010, 6, 24, 2010, 8, 4],
          NW: [2010, 7, 15, 2010, 8, 27],
          RP: [2010, 7, 5, 2010, 8, 13],
          SL: [2010, 7, 5, 2010, 8, 14],
          SN: [2010, 6, 28, 2010, 8, 26],
          ST: [2010, 6, 24, 2010, 8, 4],
          SH: [2010, 7, 12, 2010, 8, 12],
          TH: [2010, 6, 24, 2010, 8, 4],

          BGL: [2010, 7, 3, 2010, 9, 5],
          KTN: [2010, 7, 10, 2010, 9, 11],
          NOE: [2010, 7, 3, 2010, 9, 5],
          OOE: [2010, 7, 10, 2010, 9, 11],
          SBG: [2010, 7, 10, 2010, 9, 11],
          STM: [2010, 7, 10, 2010, 9, 11],
          TIR: [2010, 7, 10, 2010, 9, 11],
          VBG: [2010, 7, 10, 2010, 9, 11],
          W: [2010, 7, 3, 2010, 9, 5],

          AG: [2010, 7, 17, 2010, 8, 8],
          AR: [2010, 7, 3, 2010, 8, 8],
          AI: [2010, 7, 3, 2010, 8, 15],
          BL: [2010, 6, 26, 2010, 8, 8],
          BS: [2010, 6, 26, 2010, 8, 8],
          BR: [2010, 7, 3, 2010, 8, 15],
          FR: [2010, 7, 5, 2010, 8, 29],
          GE: [2010, 7, 3, 2010, 8, 29],
          GL: [2010, 7, 3, 2010, 8, 15],
          GR: [2010, 7, 3, 2010, 8, 22],
          JU: [2010, 7, 3, 2010, 8, 15],
          LU: [2010, 7, 10, 2010, 8, 22],
          NE: [2010, 7, 3, 2010, 8, 15],
          ND: [2010, 7, 3, 2010, 8, 15],
          OW: [2010, 7, 3, 2010, 8, 15],
          SF: [2010, 7, 10, 2010, 8, 15],
          SZ: [2010, 7, 10, 2010, 8, 15],
          SO: [2010, 7, 10, 2010, 8, 15],
          SG: [2010, 7, 3, 2010, 8, 8],
          TI: [2010, 6, 18, 2010, 8, 29],
          TG: [2010, 7, 10, 2010, 8, 15],
          UR: [2010, 7, 3, 2010, 8, 15],
          VD: [2010, 7, 2, 2010, 8, 22],
          VS: [2010, 6, 25, 2010, 8, 15],
          ZG: [2010, 7, 3, 2010, 8, 15],
          ZH: [2010, 7, 17, 2010, 8, 22]
        }),
        new this(2010, 'Herbstferien', {
          BW: [2010, 11, 2, 2010, 11, 6],
          BY: [2010, 11, 2, 2010, 11, 5],
          BE: [2010, 10, 11, 2010, 10, 23],
          BB: [2010, 10, 11, 2010, 10, 23],
          HB: [2010, 10, 9, 2010, 10, 23],
          HH: [2010, 10, 4, 2010, 10, 15],
          HE: [2010, 10, 11, 2010, 10, 22],
          MV: [2010, 10, 18, 2010, 10, 23],
          NI: [2010, 10, 9, 2010, 10, 23],
          NW: [2010, 10, 11, 2010, 10, 23],
          RP: [2010, 10, 11, 2010, 10, 22],
          SL: [2010, 10, 11, 2010, 10, 23],
          SN: [2010, 10, 4, 2010, 10, 16],
          ST: [2010, 10, 18, 2010, 10, 23],
          SH: [2010, 10, 11, 2010, 10, 23],
          TH: [2010, 10, 9, 2010, 10, 23],


          AG: [2010, 10, 4, 2010, 10, 15],
          AR: [2010, 10, 9, 2010, 10, 24],
          AI: [2010, 10, 9, 2010, 10, 24],
          BL: [2010, 9, 25, 2010, 10, 10],
          BS: [2010, 9, 25, 2010, 10, 9],
          BR: [2010, 9, 25, 2010, 10, 17],
          FR: [2010, 10, 16, 2010, 11, 1],
          GE: [2010, 10, 23, 2010, 10, 31],
          GL: [2010, 10, 9, 2010, 10, 24],
          GR: [2010, 10, 9, 2010, 10, 24],
          JU: [2010, 10, 2, 2010, 10, 17],
          LU: [2010, 10, 2, 2010, 10, 17],
          NE: [2010, 10, 2, 2010, 10, 17],
          ND: [2010, 9, 25, 2010, 10, 10],
          OW: [2010, 9, 25, 2010, 10, 10],
          SF: [2010, 10, 2, 2010, 10, 24],
          SZ: [2010, 10, 2, 2010, 10, 17],
          SO: [2010, 10, 2, 2010, 10, 24],
          SG: [2010, 9, 25, 2010, 10, 17],
          TI: [2010, 10, 30, 2010, 11, 7],
          TG: [2010, 10, 9, 2010, 10, 24],
          UR: [2010, 10, 2, 2010, 10, 17],
          VD: [2010, 10, 15, 2010, 10, 31],
          VS: [2010, 10, 9, 2010, 10, 24],
          ZG: [2010, 10, 2, 2010, 10, 17],
          ZH: [2010, 10, 9, 2010, 10, 24]
        }),
        new this(2010, 'Weihnachtsferien', {
          BW: [2010, 12, 23, 2011, 1, 8],
          BY: [2010, 12, 24, 2011, 1, 7],
          BE: [2010, 12, 23, 2011, 1, 1],
          BB: [2010, 12, 23, 2011, 1, 1],
          HB: [2010, 12, 22, 2011, 1, 5],
          HH: [2010, 12, 23, 2011, 1, 3],
          HE: [2010, 12, 20, 2011, 1, 7],
          MV: [2010, 12, 23, 2010, 12, 31],
          NI: [2010, 12, 22, 2011, 1, 5],
          NW: [2010, 12, 24, 2011, 1, 8],
          RP: [2010, 12, 23, 2011, 1, 7],
          SL: [2010, 12, 20, 2011, 1, 1],
          SN: [2010, 12, 23, 2011, 1, 1],
          ST: [2010, 12, 22, 2011, 1, 5],
          SH: [2010, 12, 23, 2011, 1, 7],
          TH: [2010, 12, 23, 2011, 1, 1],

          BGL: w_at_10,
          KTN: w_at_10,
          NOE: w_at_10,
          OOE: w_at_10,
          SBG: w_at_10,
          STM: w_at_10,
          TIR: w_at_10,
          VBG: w_at_10,
          W: w_at_10,

          AG: [2010, 12, 24, 2011, 1, 7],
          AR: [2010, 12, 24, 2011, 1, 2],
          AI: [2010, 12, 24, 2011, 1, 2],
          BL: [2010, 12, 24, 2011, 1, 2],
          BS: [2010, 12, 24, 2011, 1, 1],
          BR: [2010, 12, 25, 2011, 1, 9],
          FR: [2010, 12, 24, 2011, 1, 9],
          GE: [2010, 12, 24, 2011, 1, 9],
          GL: [2010, 12, 24, 2011, 1, 9],
          GR: [2010, 12, 24, 2011, 1, 9],
          JU: [2010, 12, 24, 2011, 1, 3],
          LU: [2010, 12, 24, 2011, 1, 3],
          NE: [2010, 12, 24, 2011, 1, 9],
          ND: [2010, 12, 25, 2011, 1, 2],
          OW: [2010, 12, 24, 2011, 1, 4],
          SF: [2010, 12, 24, 2011, 1, 2],
          SZ: [2010, 12, 24, 2011, 1, 9],
          SO: [2010, 12, 25, 2011, 1, 9],
          SG: [2010, 12, 24, 2011, 1, 2],
          TI: [2010, 12, 24, 2011, 1, 2],
          TG: [2010, 12, 24, 2011, 1, 2],
          UR: [2010, 12, 24, 2011, 1, 9],
          VD: [2010, 12, 23, 2011, 1, 9],
          VS: [2010, 12, 24, 2011, 1, 9],
          ZG: [2010, 12, 23, 2011, 1, 5],
          ZH: [2010, 12, 24, 2011, 1, 3]
        }),



        new this(2011, 'Sportferien', {

          AR: [2011, 1, 30, 2011, 2,  6],
          AI: [2011, 2, 19, 2011, 2, 27],
          BL: [2011, 3,  5, 2011, 3, 20],
          BS: [2011, 3,  5, 2011, 3, 19],
          FR: [2011, 3,  5, 2011, 3, 13],
          GE: [2011, 2, 19, 2011, 2, 27],
          GL: [2011, 1, 29, 2011, 2,  6],
          GR: [2011, 2, 26, 2011, 3,  6],
          JU: [2011, 2, 12, 2011, 2, 20],
          LU: [2011, 2, 26, 2011, 3, 13],
          NE: [2011, 2, 26, 2011, 3,  6],
          ND: [2011, 2, 26, 2011, 3, 13],
          OW: [2011, 2, 26, 2011, 3, 13],
          SF: [2011, 1, 29, 2011, 2, 13],
          SZ: [2011, 2, 26, 2011, 3,  6],
          SO: [2011, 2,  5, 2011, 2, 20],
		  TI: [2011, 3,  5, 2011, 3, 13],
          TG: [2011, 1, 29, 2011, 2,  6],
          UR: [2011, 2, 26, 2011, 3,  8],
          VD: [2011, 2, 25, 2011, 3,  6],
          VS: [2011, 1, 21, 2011, 2,  6],
          ZG: [2011, 2,  5, 2011, 2, 20],
          ZH: [2011, 2,  5, 2011, 2, 20]
        }),
        new this(2011, 'Frühlingsferien', {

          AG: [2011, 4, 11, 2011, 4, 21],
          AR: [2011, 4, 10, 2011, 4, 25],
          AI: [2011, 4,  9, 2011, 4, 25],
          BL: [2011, 4, 21, 2011, 5,  1],
          BS: [2011, 4, 21, 2011, 4, 30],
          BR: [2011, 4,  9, 2011, 4, 25],
          FR: [2011, 4, 16, 2011, 5,  1],
          GE: [2011, 4, 21, 2011, 5,  1],
          GL: [2011, 4,  7, 2011, 4, 25],
          GR: [2011, 4, 22, 2011, 5, 15],
          JU: [2011, 4,  9, 2011, 4, 27],
          LU: [2011, 4, 22, 2011, 5,  8],
          NE: [2011, 4,  9, 2011, 4, 25],
          ND: [2011, 4, 22, 2011, 5,  8],
          OW: [2011, 4, 21, 2011, 5,  8],
          SF: [2011, 4, 16, 2011, 5,  1],
          SZ: [2011, 4, 30, 2011, 5, 15],
          SO: [2011, 4,  9, 2011, 4, 25],
          SG: [2011, 4,  9, 2011, 4, 25],
          TI: [2011, 4, 22, 2011, 5,  1],
          TG: [2011, 4,  9, 2011, 4, 25],
          UR: [2011, 4, 22, 2011, 5,  8],
          VD: [2011, 4, 15, 2011, 5,  1],
          VS: [2011, 4, 22, 2011, 5,  8],
          ZG: [2011, 4, 16, 2011, 5,  1],
          ZH: [2011, 4, 16, 2011, 5,  1]
        }),
        new this(2011, 'Winterferien', {
          BY: [2011, 3, 7, 2011, 3, 11],
          BE: [2011, 1, 31, 2011, 2, 5],
          BB: [2011, 1, 31, 2011, 2, 5],
          HB: [2011, 1, 31, 2011, 2, 1],
          HH: [2011, 1, 31, 2011, 1, 31],
          MV: [2011, 2, 7, 2011, 2, 19],
          NI: [2011, 1, 31, 2011, 2, 1],
          SL: [2011, 3, 7, 2011, 3, 12],
          SN: [2011, 2, 12, 2011, 2, 26],
          ST: [2011, 2, 5, 2011, 2, 12],
          TH: [2011, 1, 31, 2011, 2, 5]

        }),
        new this(2011, 'Osterferien', {
          BW: [2011, 4, 26, 2011, 4, 30],
          BY: [2011, 4, 18, 2011, 4, 30],
          BE: [2011, 4, 18, 2011, 4, 30],
          BB: [2011, 4, 20, 2011, 4, 30],
          HB: [2011, 4, 16, 2011, 4, 30],
          HH: [2011, 3,  7, 2011, 3, 18],
          HE: [2011, 4, 18, 2011, 4, 30],
          MV: [2011, 4, 16, 2011, 4, 27],
          NI: [2011, 4, 16, 2011, 4, 30],
          NW: [2011, 4, 18, 2011, 4, 30],
          RP: [2011, 4, 18, 2011, 4, 29],
          SL: [2011, 4, 18, 2011, 4, 30],
          SN: [2011, 4, 22, 2011, 4, 30],
          ST: [2011, 4, 18, 2011, 4, 27],
          SH: [2011, 4, 15, 2011, 4, 30],
          TH: [2011, 4, 18, 2011, 4, 30],

          BGL: o_at_11,
          KTN: o_at_11,
          NOE: o_at_11,
          OOE: o_at_11,
          SBG: o_at_11,
          STM: o_at_11,
          TIR: o_at_11,
          VBG: o_at_11,
          W:   o_at_11

        }),
        new this(2011, 'Pfingstferien', {
          BW: [2011, 6, 14, 2011, 6, 25],
          BY: [2011, 6, 14, 2011, 6, 25],
          BE: [2011, 6, 3, 2011, 6, 3],
          BB: [2011, 6, 3, 2011, 6, 3],
          HB: [2011, 6, 3, 2011, 6, 3],
          HH: [2011, 4, 26, 2011, 4, 29],
          MV: [2011, 6, 10, 2011, 6, 14],
          NI: [2011, 6, 3, 2011, 6, 3],
          SN: [2011, 6, 3, 2011, 6, 3],
          ST: [2011, 6, 14, 2011, 6, 18],
          SH: [2011, 6, 3, 2011, 6, 3],
          TH: [2011, 6, 11, 2011, 6, 14],

          BGL: p_at_11,
          KTN: p_at_11,
          NOE: p_at_11,
          OOE: p_at_11,
          SBG: p_at_11,
          STM: p_at_11,
          TIR: p_at_11,
          VBG: p_at_11,
          W:   p_at_11

        }),
        new this(2011, 'Sommerferien', {
          BW: [2011, 7, 28, 2011, 9, 10],
          BY: [2011, 7, 30, 2011, 9, 12],
          BE: [2011, 6, 30, 2011, 8, 12],
          BB: [2011, 6, 30, 2011, 8, 13],
          HB: [2011, 7, 7, 2011, 8, 17],
          HH: [2011, 6, 30, 2011, 8, 10],
          HE: [2011, 6, 27, 2011, 8, 5],
          MV: [2011, 7, 4, 2011, 8, 13],
          NI: [2011, 7, 7, 2011, 8, 17],
          NW: [2011, 7, 25, 2011, 8, 6],
          RP: [2011, 6, 27, 2011, 8, 5],
          SL: [2011, 6, 24, 2011, 8, 6],
          SN: [2011, 7, 11, 2011, 8, 19],
          ST: [2011, 7, 11, 2011, 8, 24],
          SH: [2011, 7, 4, 2011, 8, 13],
          TH: [2011, 6, 11, 2011, 8, 19],

          BGL: [2011, 7, 2, 2011, 9, 3],
          KTN: [2011, 7, 9, 2011, 9, 10],
          NOE: [2011, 7, 2, 2011, 9, 3],
          OOE: [2011, 7, 9, 2011, 9, 10],
          SBG: [2011, 7, 9, 2011, 9, 10],
          STM: [2011, 7, 9, 2011, 9, 10],
          TIR: [2011, 7, 9, 2011, 9, 10],
          VBG: [2011, 7, 9, 2011, 9, 10],
          W: [2011, 7, 2, 2011, 9, 3],

          AG: [2011, 7, 18, 2011, 8,  5],
          AR: [2011, 7, 10, 2011, 8, 14],
          AI: [2011, 7,  2, 2011, 8, 15],
          BL: [2011, 7,  2, 2011, 8, 14],
          BS: [2011, 7,  2, 2011, 8, 14],
          BR: [2011, 7,  2, 2011, 8, 14],
          FR: [2011, 7,  9, 2011, 9,  4],
          GE: [2011, 7,  2, 2011, 8, 28],
          GL: [2011, 7,  2, 2011, 8, 14],
          GR: [2011, 7,  3, 2011, 8, 21],
          JU: [2011, 7,  2, 2011, 8, 21],
          LU: [2011, 7,  9, 2011, 8, 21],
          NE: [2011, 7,  2, 2011, 8, 14],
          ND: [2011, 7,  2, 2011, 8, 28],
          OW: [2011, 7,  1, 2011, 8, 15],
          SF: [2011, 7,  9, 2011, 8, 14],
          SZ: [2011, 7,  9, 2011, 8, 14],
          SO: [2011, 7,  9, 2011, 8, 15],
          SG: [2011, 7,  9, 2011, 8, 14],
          TI: [2011, 7, 17, 2011, 8, 29],
          TG: [2011, 7,  9, 2011, 8, 14],
          UR: [2011, 7,  2, 2011, 8, 15],
          VD: [2011, 7,  2, 2011, 8, 21],
          VS: [2011, 7,  1, 2011, 8, 21],
          ZG: [2011, 7,  9, 2011, 8, 21],
          ZH: [2011, 7,  9, 2011, 8, 21]
        }),
        new this(2011, 'Herbstferien', {
          BW: [2011, 11, 2, 2011, 11, 4],
          BY: [2011, 10, 31, 2011, 11, 5],
          BE: [2011, 10, 4, 2011, 10, 14],
          BB: [2011, 10, 4, 2011, 10, 14],
          HB: [2011, 10, 17, 2011, 10, 29],
          HH: [2011, 10, 4, 2011, 10, 14],
          HE: [2011, 10, 10, 2011, 10, 22],
          MV: [2011, 10, 17, 2011, 10, 21],
          NI: [2011, 10, 17, 2011, 10, 29],
          NW: [2011, 10, 24, 2011, 11, 5],
          RP: [2011, 10, 4, 2011, 10, 14],
          SL: [2011, 10, 4, 2011, 10, 15],
          SN: [2011, 10, 17, 2011, 10, 28],
          ST: [2011, 10, 17, 2011, 10, 22],
          SH: [2011, 10, 10, 2011, 10, 22],
          TH: [2011, 10, 17, 2011, 10, 28],


          AG: [2011, 10,  3, 2011, 10, 14],
          AR: [2011, 10,  9, 2011, 10, 23],
          AI: [2011, 10,  8, 2011, 10, 23],
          BL: [2011, 10,  1, 2011, 10, 23],
          BS: [2011, 10,  1, 2011, 10, 16],
          BR: [2011,  9, 24, 2011, 10, 16],
          FR: [2011, 10, 15, 2011, 11,  2],
          GE: [2011, 10, 22, 2011, 10, 30],
          GL: [2011, 10,  8, 2011, 10, 23],
          GR: [2011, 10,  1, 2011, 10, 23],
          JU: [2011, 10,  8, 2011, 10, 23],
          LU: [2011, 10,  1, 2011, 10, 16],
          NE: [2011, 10,  1, 2011, 10, 16],
          ND: [2011, 10,  1, 2011, 10, 16],
          OW: [2011, 10,  8, 2011, 10, 30],
          SF: [2011, 10,  1, 2011, 10, 23],
          SZ: [2011, 10,  1, 2011, 10, 16],
          SO: [2011, 10,  1, 2011, 10, 23],
          SG: [2011, 10,  1, 2011, 10, 23],
          TI: [2011, 10, 29, 2011, 11,  6],
          TG: [2011, 10,  8, 2011, 10, 23],
          UR: [2011, 10,  1, 2011, 10, 16],
          VD: [2011, 10, 14, 2011, 10, 30],
          VS: [2011, 10,  8, 2011, 10, 23],
          ZG: [2011, 10,  8, 2011, 10, 23],
          ZH: [2011, 10, 10, 2011, 10, 23]
        }),
        new this(2011, 'Weihnachtsferien', {
          BW: [2011, 12, 23, 2012, 1, 5],
          BY: [2011, 12, 27, 2012, 1, 5],
          BE: [2011, 12, 23, 2012, 1, 3],
          BB: [2011, 12, 23, 2012, 1, 3],
          HB: [2011, 12, 23, 2012, 1, 4],
          HH: [2011, 12, 27, 2012, 1, 6],
          HE: [2011, 12, 21, 2012, 1, 6],
          MV: [2011, 12, 22, 2012, 1, 3],
          NI: [2011, 12, 23, 2012, 1, 4],
          NW: [2011, 12, 23, 2012, 1, 6],
          RP: [2011, 12, 22, 2012, 1, 6],
          SL: [2011, 12, 23, 2012, 1, 4],
          SN: [2011, 12, 23, 2012, 1, 2],
          ST: [2011, 12, 22, 2012, 1, 7],
          SH: [2011, 12, 23, 2012, 1, 6],
          TH: [2011, 12, 23, 2012, 1, 1],

          BGL: w_at_11,
          KTN: w_at_11,
          NOE: w_at_11,
          OOE: w_at_11,
          SBG: w_at_11,
          STM: w_at_11,
          TIR: w_at_11,
          VBG: w_at_11,
          W: w_at_11,

          AG: [2011, 12, 26, 2012, 1, 6],
          AR: [2011, 12, 24, 2012, 1, 2],
          AI: [2011, 12, 24, 2012, 1, 2],
          BL: [2011, 12, 24, 2012, 1, 2],
          BS: [2011, 12, 24, 2012, 1, 2],
          BR: [2011, 12, 24, 2012, 1, 8],
          FR: [2011, 12, 24, 2012, 1, 8],
          GE: [2011, 12, 24, 2012, 1, 8],
          GL: [2011, 12, 24, 2012, 1, 8],
          GR: [2011, 12, 24, 2012, 1, 8],
          JU: [2011, 12, 24, 2012, 1, 8],
          LU: [2011, 12, 24, 2012, 1, 8],
          NE: [2011, 12, 24, 2012, 1, 8],
          ND: [2011, 12, 24, 2012, 1, 2],
          OW: [2011, 12, 24, 2012, 1, 4],
          SF: [2011, 12, 24, 2012, 1, 2],
          SZ: [2011, 12, 24, 2012, 1, 8],
          SO: [2011, 12, 24, 2012, 1, 8],
          SG: [2011, 12, 24, 2012, 1, 2],
          TI: [2011, 12, 24, 2012, 1, 8],
          TG: [2011, 12, 24, 2012, 1, 2],
          UR: [2011, 12, 24, 2012, 1, 8],
          VD: [2011, 12, 23, 2012, 1, 8],
          VS: [2011, 12, 24, 2012, 1, 8],
          ZG: [2011, 12, 22, 2012, 1, 4],
          ZH: [2011, 12, 24, 2012, 1, 3]
        })
      ];
    }
  }
});



SearchMask.Sport = new JS.Class(SearchMask.SimpleNameValuePair, {
  extend: {
    fetch_all: function() {
      return [
        new this('beliebig', -1),
        new this('großes Sportangebot', 10),
        new this('Tennis', 0),
        new this('Golf', 1),
        new this('Squash', 2),
        new this('Radsport', 3),
        new this('Wassersport', 4),
        new this('Tauchen', 5),
        new this('Reiten', 6),
        new this('Wandern', 7),
        new this('Surfen', 8)
      ];
    },
    element_selector: '#sport_id',
    underscore_class_name: 'sport',
    tt_key: 'sportangebot'
  }
});


SearchMask.State = new JS.Class(SearchMask.SimpleNameValuePair, {
  country_name: function() {
    return this.country.name;
  },
  extend: {
    all_states_with_misc: function() {
      var ret = [new SM.State("Bundesland wählen", "all")];
      $.each(SM.Country.fetch_entries(), function(index, country) {
        ret.push(country);
        ret = $.merge(ret, country.states);
      });
      return ret;
    },
    all_state_ids: function(country_id){
      var ret = [];
      if(country_id === undefined){
        $.each(this.all_states_with_misc(), function(i, state){
          ret.push(state.value);
        });
      }else{
        $.each(SM.Country.find_by_id(country_id).states, function(i, state){
          ret.push(state.value);
        });
      }
      return ret;
    }
  }
});

SearchMask.Country = new JS.Class({
  initialize: function(name, value, states) {
    var self = this;
    this.name = name;
    this.value = value;
    this.states = states;
    this.type = this.klass.underscore_class_name;

    $.each(this.states, function(idx, state) {
      state.country = self;
    });
  },
  get_value: function(){
    return this.value;
  },
  extend: {
    find_by_id: function(id){
      var ret = null;
      $.each(SM.Country.fetch_entries(), function(i, country){
        if(country.value == id){
          ret = country;
        }
      });
      return ret;
    },
    underscore_class_name: 'country',
    fetch_entries: function() {
      var S = SearchMask.State;
      return [
        new this('Deutschland', 'DE', [
          new S('Baden-Württemberg', 'BW'),
          new S('Bayern', 'BY'),
          new S('Berlin', 'BE'),
          new S('Brandenburg', 'BB'),
          new S('Bremen', 'HB'),
          new S('Hamburg', 'HH'),
          new S('Hessen', 'HE'),
          new S('Mecklenburg-Vorpommern', 'MV'),
          new S('Niedersachsen', 'NI'),
          new S('Nordrhein-Westfalen', 'NW'),
          new S('Rheinland-Pfalz', 'RP'),
          new S('Saarland', 'SL'),
          new S('Sachsen', 'SN'),
          new S('Sachsen-Anhalt', 'ST'),
          new S('Schleswig-Holstein', 'SH'),
          new S('Thüringen', 'TH')
        ]),
        new this('Österreich', 'AT', [
          new S('Burgenland', 'BGL'),
          new S('Kärnten', 'KTN'),
          new S('Niederösterreich', 'NOE'),
          new S('Oberösterreich', 'OOE'),
          new S('Salzburg', 'SBG'),
          new S('Steiermark', 'STM'),
          new S('Tirol', 'TIR'),
          new S('Vorarlberg', 'VBG'),
          new S('Wien', 'W')
        ]),
        new this('Schweiz', 'CH', [
          new S('Aargau', 'AG'),
          new S('Appenzell Ausserrhoden', 'AR'),
          new S('Appenzell Innerrhoden', 'AI'),
          new S('Basel-Landschaft', 'BL'),
          new S('Basel-Stadt', 'BS'),
          new S('Bern', 'BR'),
          new S('Freiburg', 'FR'),
          new S('Genf', 'GE'),
          new S('Glarus', 'GL'),
          new S('Graubünden', 'GR'),
          new S('Jura', 'JU'),
          new S('Luzern', 'LU'),
          new S('Neuenburg', 'NE'),
          new S('Nidwalden', 'ND'),
          new S('Obwalden', 'OW'),
          new S('Schaffhausen', 'SF'),
          new S('Schwyz', 'SZ'),
          new S('Solothurn', 'SO'),
          new S('St. Gallen', 'SG'),
          new S('Tessin', 'TI'),
          new S('Thurgau', 'TG'),
          new S('Uri', 'UR'),
          new S('Waadt', 'VD'),
          new S('Wallis', 'VS'),
          new S('Zug', 'ZG'),
          new S('Zürich', 'ZH')
        ])
      ];
    }
  }
});


SearchMask.Theme = new JS.Class(SearchMask.FinderLogic, {
  initialize: function(name, id, bit1, bit2) {
    this.name = name;
    this.id = id;
    this.bit1 = bit1;
    this.bit2 = bit2;
  },
  put_to_form: function(form) {
    var selector = this.callSuper(form);
    $(document).bind("earth_ready", function() { selector.change(); });
  },
  to_url_params: function() {
    var hash = {};
    if(this.bit1 !== true) {
      hash.HotelBit1 = this.bit1;
    }
    if(this.bit2 !== true) {
      hash.HotelBit2 = this.bit2;
    }
    return hash;
  },
  get_value: function() {
    return this.id;
  },
  associated_countries : function() {
    return SearchMask.DestinationEarth.find_by_hotelbits(this.bit1, this.bit2);
  },
  extend: {
    fetch_all: function() {
      return [
        new this('beliebig', 1, true, true),
        new this('Golf', 2, 9, true),
        new this('Wellness', 3, 12, true),
        new this('Urlaub in den Bergen', 4, true, 1),
        new this('Ski', 5, 10, true),
        new this('Badeurlaub Nord- & Ostsee', 6, 13, true),
        new this('Badeurlaub am Mittelmeer', 7, 14, true),
        new this('Badeurlaub in der Ferne', 8, 15, true),
        new this('Familienurlaub', 9, 3, true),
        new this('Urlaub in Deutschland', 10, 11, true),
        new this('Urlaub in Österreich', 11, 16, true),
        new this('Städtereisen', 12, 4, 4),
        new this('Freizeitparks', 13, 5, 5),
        new this('Disneyland Paris (FR)', 14, 1, 5),
        new this('Legoland Billund (DK)', 15, 2, 5),
        new this('Legoland Deutschland', 16, 3, 5),
        new this('Movie Park Germany', 17, 4, 5),
        new this('Phantasialand', 18, 5, 5),
        new this('Heidepark Soltau', 19, 6, 5),
        new this('Hansa Park', 20, 7, 5),
        new this('Europa Park', 21, 8, 5)
      ];
    },
    element_selector: '#theme_id',
    underscore_class_name: 'theme',

    find_by_bit: function(pos, bit) {
      return $.detect(this.find_all(), function(o) {
        return (o["bit"+pos] === bit);
      });
    },
    find_by_url_param: function(param) {
      return this.find_by_bit.apply(this, param);
    }
  }
});

SearchMask.Travelers = new JS.Class(SearchMask.FinderLogic, {
  initialize: function(name, adult_count, children_with_age) {
    this.name = name;
    this.adult_count = adult_count;
    this.set_children(children_with_age);
  },
  set_children: function(children_with_age) {
    this.children_with_age = children_with_age;
    if(typeof(this.children_with_age) === "undefined") {
      this.children_with_age = [];
    }
    this.children_with_age.sort(function(a, b) {return a - b;});
  },
  put_children_to_form: function(form) {
    for(var i = 1; i <= 3; i++) {
      var age = this.children_with_age[i - 1];
      if(age === 0) {
        age = 1;
      }
      if(typeof(age) === 'undefined') {
        age = -1;
      }else{
        $('#child').attr('checked', true);
      }
      $('#child_' + i, form).val(age);
    }
  },
  to_url_params: function() {
    var arr = [25, 25, 25, 25].slice(0, this.adult_count);

    for(var i = 0; i < this.children_with_age.length; i++) {
      arr.push(this.children_with_age[i]);
    }

    return {personen: arr.join(';')};
  },
  validate: function(form_element, form_state) {
    if(this.adult_count > 4) {
      this.klass.find_all()[3].put_to_form(form_element);
      $(form_state).trigger('travelers_too_many_adults');
    }
  },
  get_value: function(){
    return this.adult_count;
  },
  extend: {
    fetch_all: function() {
      return [
        new this('1 Erwachsener', 1),
        new this('2 Erwachsene', 2),
        new this('3 Erwachsene', 3),
        new this('4 Erwachsene', 4),
        new this('mehr', 5)
      ];
    },
    find_by_adult_count: function(adult_count) {
      return $.detect(this.find_all(), function(obj) {
        return obj.adult_count == adult_count;
      });
    },
    find_by_form: function(form) {

      var ages = [];
      for(var i = 1; i <= 3; i++) {
        var x = $('#child_' + i, form).val();
        x = parseInt(x, 10);
        if(!isNaN(x) && x > -1) {
          ages.push(x);
        }
      }

      var obj = this.find_by_adult_count($('#traveler', form).val());

      obj = $.extend(true, {}, obj);
      obj.set_children(ages);

      return obj;
    },
    default_entry: function() {
      return this.find_all()[1];
    },
    from_url_params: function(params) {
      var adult_count = 0;
      var children = [];

      var arr = params.travelers;
      if(typeof(arr) !== 'undefined') {
        for(var i = 0; i < arr.length; i++) {
          if(arr[i] >= 17) {
            adult_count++;
          } else {
            children.push(arr[i]);
          }
        }
      }
      if(adult_count === 0) {
        return this.default_entry();
      }
      else {
        var obj = this.find_by_adult_count(adult_count);
        obj = $.extend(true, {}, obj);
        obj.set_children(children);
        return obj;
      }
    },
    fetch_all_children_ages: function() {
      var ret = [
        {name: '-', value: -1},
        {name: '< 2 Jahre', value: 1}
      ];
      for(var i = 2; i <= 16; i++) {
        ret.push({name: i + ' Jahre', value: i});
      }
      return ret;
    },
    find_all_children_ages: function() {
      if(typeof(this.all_children_age_objects) === 'undefined') {
        this.all_children_age_objects = this.fetch_all_children_ages();
      }
      return this.all_children_age_objects;
    },
    element_selector: '#traveler',
    underscore_class_name: 'travelers'
  }
});
SearchMask.AirportController = new JS.Singleton({
  initialize: function(){
    this.events_registered = false;
  },
  airport: function(caller) {
    this.caller = caller;

    this.airport_events();

    caller.form_state.put_one(SearchMask.DepartureAirport);

    $('#airportbox input[type="checkbox"]:checked').trigger('change');
    $('#airportbox_pos').show();
  },
  airport_close_event: function() {
    this.update_airport_status_text(this.caller.form_state);
    $('#airportbox_pos').hide();
  },
  airport_events: function(){
    if(!this.events_registered){
      var self = this;
       $('#airportbox_pos span.s_closepopup').click(function() {
        self.select_default_airport();
        self.airport_close_event.call(self);
      });
      $('#airportbox_pos input[type="button"]').click(function() {
        self.airport_close_event.call(self);
      });
      this.airport_selector(this.default_airport()).change(function(event) {
        self.default_airport_selected(event.target);
      });
      this.for_each_virtual_airport(function(airport) {
        self.airport_selector(airport).change(function(event) {
          self.virtual_airport_selected(airport, event.target);
        });
      });
      this.for_each_real_airport(function(airport) {
        self.airport_image_selector(airport).tinyTips('light', airport.name);
        self.airport_selector(airport).change(function(event) {
          self.real_airport_selected(airport, event.target);
        });
      });
      this.events_registered = true;
    }
  },
  default_airport_selected: function(element) {
    $('#img_airport_-1').removeClass();
    $('#img_airport_-1').addClass("s_mapon");
    var self = this;

    if(!element.checked) {
      element.checked = true;
    }

    this.for_each_virtual_airport(function(airport) {
      self.set_airport_disabled(airport, false);
      self.set_airport_checked(airport, false);
    });

    this.for_each_real_airport(function(airport) {
      self.set_airport_disabled(airport, false);
      self.set_airport_checked(airport, false);
    });
  },
  select_default_airport: function() {
    var ele = this.airport_selector(this.default_airport())[0];
    this.default_airport_selected(ele);
  },
  virtual_airport_selected: function(ap, element) {
    this.set_airport_checked(ap, element.checked);
    var self = this;

    if(!element.checked) {
      this.select_default_airport();
      return;
    }

    this.set_airport_checked(this.default_airport(), false);

    this.for_each_virtual_airport(function(airport) {
      if(airport.value != ap.value) {
        self.set_airport_checked(airport, false);
      }
    });

    this.for_each_real_airport(function(airport) {
      var checked = ap.has_associated_airport_with_key(airport.value) &&
                    element.checked ? 'checked' : '';
      self.set_airport_checked(airport, checked);

      self.set_airport_disabled(airport, element.checked);
    });
  },
  real_airport_selected: function(ap, element) {
    this.set_airport_checked(ap, element.checked);

    var self = this;
    var checked_count = $('#airportbox input[type="checkbox"]:checked').length;

    if(checked_count === 0) {
      this.select_default_airport();
      return;
    }

    self.set_airport_checked(this.default_airport(), false);

    this.for_each_virtual_airport(function(airport) {
      self.set_airport_checked(airport, false);
    });

    this.for_each_real_airport(function(airport) {
      var sel = self.airport_selector(airport);
      var sel_img = self.airport_image_selector(airport);
      if(checked_count >= 3 && !sel.attr('checked')){
        sel[0].disabled = true;
        if(sel[0].checked){
          sel_img.removeClass();
          sel_img.addClass("s_mapon_deact");
        }else{
          sel_img.removeClass();
          sel_img.addClass("s_mapdeact");
        }
      }else{
        sel[0].disabled = false;
        if(sel[0].checked){
          sel_img.removeClass();
          sel_img.addClass("s_mapon");
        }
        else{
          sel_img.removeClass();
          sel_img.addClass("s_mapoff");
        }
      }
    });
  },
  airport_selector: function(airport) {
    return $('#airportbox input#' + airport.element_id());
  },
  airport_image_selector: function(airport) {
    return $('#airportbox span#img_' + airport.element_id());
  },
  set_airport_checked: function(airport, checked) {
    this.airport_selector(airport)[0].checked = checked;
    if(checked === false || checked.length <= 0){
      this.airport_image_selector(airport).removeClass();
      this.airport_image_selector(airport).addClass("s_mapoff");
    }else{
      this.airport_image_selector(airport).removeClass();
      this.airport_image_selector(airport).addClass("s_mapon");
    }
  },
  set_airport_disabled: function(airport, disabled) {
    var is_checked = this.airport_selector(airport)[0].checked;
    this.airport_selector(airport)[0].disabled = disabled;
    if(disabled){
      if(is_checked){
        this.airport_image_selector(airport).removeClass();
        this.airport_image_selector(airport).addClass("s_mapon_deact");
      }else{
        this.airport_image_selector(airport).removeClass();
        this.airport_image_selector(airport).addClass("s_mapdeact");
      }
    }else{
      if(is_checked){
        this.airport_image_selector(airport).removeClass();
        this.airport_image_selector(airport).addClass("s_mapon");
      }else{
        this.airport_image_selector(airport).removeClass();
        this.airport_image_selector(airport).addClass("s_mapoff");
      }
    }
  },
  default_airport: function() {
    return SearchMask.DepartureAirport.find_default_entry();
  },
  for_each_virtual_airport: function(func) {
    $.each(SearchMask.DepartureAirport.find_all_virtual_entries(),
           function(index, obj) {
      func(obj);
    });
  },
  for_each_real_airport: function(func) {
    $.each(SearchMask.DepartureAirport.find_all_real_entries(),
        function(index, obj) {
      func(obj);
    });
  },
  update_airport_status_text: function(form_state) {
    form_state.get_one(SearchMask.DepartureAirport);
    var status = form_state.departure_airport.to_string();

    if(status.length > 20) {
      status = status.substr(0, 17) + "...";
    }

    $('#departure_airport_status').empty();
    $('#departure_airport_status').val(status);
  }
});
/*
 * jQuery UI 1.5.3
 *
 * Copyright (c) 2008 Paul Bakaus (ui.jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 */

;(function($) {

$.ui = {
	plugin: {
		add: function(module, option, set) {
			var proto = $.ui[module].prototype;
			for(var i in set) {
				proto.plugins[i] = proto.plugins[i] || [];
				proto.plugins[i].push([option, set[i]]);
			}
		},
		call: function(instance, name, args) {
			var set = instance.plugins[name];
			if(!set) { return; }

			for (var i = 0; i < set.length; i++) {
				if (instance.options[set[i][0]]) {
					set[i][1].apply(instance.element, args);
				}
			}
		}
	},
	cssCache: {},
	css: function(name) {
		if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; }
		var tmp = $('<div class="ui-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');


		$.ui.cssCache[name] = !!(
			(!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) ||
			!(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
		);
		try { $('body').get(0).removeChild(tmp.get(0));	} catch(e){}
		return $.ui.cssCache[name];
	},
	disableSelection: function(el) {
		$(el).attr('unselectable', 'on').css('MozUserSelect', 'none');
	},
	enableSelection: function(el) {
		$(el).attr('unselectable', 'off').css('MozUserSelect', '');
	},
	hasScroll: function(e, a) {
		var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false;
		if (e[scroll] > 0) return true; e[scroll] = 1;
		has = e[scroll] > 0 ? true : false; e[scroll] = 0;
		return has;
	}
};



var _remove = $.fn.remove;
$.fn.remove = function() {
	$("*", this).add(this).triggerHandler("remove");
	return _remove.apply(this, arguments );
};

function getter(namespace, plugin, method) {
	var methods = $[namespace][plugin].getter || [];
	methods = (typeof methods == "string" ? methods.split(/,?\s+/) : methods);
	return ($.inArray(method, methods) != -1);
}

$.widget = function(name, prototype) {
	var namespace = name.split(".")[0];
	name = name.split(".")[1];

	$.fn[name] = function(options) {
		var isMethodCall = (typeof options == 'string'),
			args = Array.prototype.slice.call(arguments, 1);

		if (isMethodCall && getter(namespace, name, options)) {
			var instance = $.data(this[0], name);
			return (instance ? instance[options].apply(instance, args)
				: undefined);
		}

		return this.each(function() {
			var instance = $.data(this, name);
			if (isMethodCall && instance && $.isFunction(instance[options])) {
				instance[options].apply(instance, args);
			} else if (!isMethodCall) {
				$.data(this, name, new $[namespace][name](this, options));
			}
		});
	};

	$[namespace][name] = function(element, options) {
		var self = this;

		this.widgetName = name;
		this.widgetBaseClass = namespace + '-' + name;

		this.options = $.extend({}, $.widget.defaults, $[namespace][name].defaults, options);
		this.element = $(element)
			.bind('setData.' + name, function(e, key, value) {
				return self.setData(key, value);
			})
			.bind('getData.' + name, function(e, key) {
				return self.getData(key);
			})
			.bind('remove', function() {
				return self.destroy();
			});
		this.init();
	};

	$[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
};

$.widget.prototype = {
	init: function() {},
	destroy: function() {
		this.element.removeData(this.widgetName);
	},

	getData: function(key) {
		return this.options[key];
	},
	setData: function(key, value) {
		this.options[key] = value;

		if (key == 'disabled') {
			this.element[value ? 'addClass' : 'removeClass'](
				this.widgetBaseClass + '-disabled');
		}
	},

	enable: function() {
		this.setData('disabled', false);
	},
	disable: function() {
		this.setData('disabled', true);
	}
};

$.widget.defaults = {
	disabled: false
};



$.ui.mouse = {
	mouseInit: function() {
		var self = this;

		this.element.bind('mousedown.'+this.widgetName, function(e) {
			return self.mouseDown(e);
		});

		if ($.browser.msie) {
			this._mouseUnselectable = this.element.attr('unselectable');
			this.element.attr('unselectable', 'on');
		}

		this.started = false;
	},

  mouseDestroy: function() {
		this.element.unbind('.'+this.widgetName);

		($.browser.msie
			&& this.element.attr('unselectable', this._mouseUnselectable));
	},

	mouseDown: function(e) {
		(this._mouseStarted && this.mouseUp(e));

		this._mouseDownEvent = e;

		var self = this,
			btnIsLeft = (e.which == 1),
			elIsCancel = (typeof this.options.cancel == "string" ? $(e.target).parents().add(e.target).filter(this.options.cancel).length : false);
		if (!btnIsLeft || elIsCancel || !this.mouseCapture(e)) {
			return true;
		}

		this._mouseDelayMet = !this.options.delay;
		if (!this._mouseDelayMet) {
			this._mouseDelayTimer = setTimeout(function() {
				self._mouseDelayMet = true;
			}, this.options.delay);
		}

		if (this.mouseDistanceMet(e) && this.mouseDelayMet(e)) {
			this._mouseStarted = (this.mouseStart(e) !== false);
			if (!this._mouseStarted) {
				e.preventDefault();
				return true;
			}
		}

		this._mouseMoveDelegate = function(e) {
			return self.mouseMove(e);
		};
		this._mouseUpDelegate = function(e) {
			return self.mouseUp(e);
		};
		$(document)
			.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);

		return false;
	},

	mouseMove: function(e) {
		if ($.browser.msie && !e.button) {
			return this.mouseUp(e);
		}

		if (this._mouseStarted) {
			this.mouseDrag(e);
			return false;
		}

		if (this.mouseDistanceMet(e) && this.mouseDelayMet(e)) {
			this._mouseStarted =
				(this.mouseStart(this._mouseDownEvent, e) !== false);
			(this._mouseStarted ? this.mouseDrag(e) : this.mouseUp(e));
		}

		return !this._mouseStarted;
	},

	mouseUp: function(e) {
		$(document)
			.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);

		if (this._mouseStarted) {
			this._mouseStarted = false;
			this.mouseStop(e);
		}

		return false;
	},

	mouseDistanceMet: function(e) {
		return (Math.max(
				Math.abs(this._mouseDownEvent.pageX - e.pageX),
				Math.abs(this._mouseDownEvent.pageY - e.pageY)
			) >= this.options.distance
		);
	},

	mouseDelayMet: function(e) {
		return this._mouseDelayMet;
	},

	mouseStart: function(e) {},
	mouseDrag: function(e) {},
	mouseStop: function(e) {},
	mouseCapture: function(e) { return true; }
};

$.ui.mouse.defaults = {
	cancel: null,
	distance: 1,
	delay: 0
};

})(jQuery);
/*
 * jQuery UI Datepicker
 *
 * Copyright (c) 2006, 2007, 2008 Marc Grabanski
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Datepicker
 *
 * Depends:
 *	ui.core.js
 *
 * Marc Grabanski (m@marcgrabanski.com) and Keith Wood (kbwood@virginbroadband.com.au).
 */

(function($) { // hide the namespace

var PROP_NAME = 'datepicker';

/* Date picker manager.
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
   Settings for (groups of) date pickers are maintained in an instance object,
   allowing multiple different settings on the same page. */

function Datepicker() {
	this.debug = false; // Change this to true to start debugging
	this._curInst = null; // The current instance in use
	this._disabledInputs = []; // List of date picker inputs that have been disabled
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
	this._inDialog = false; // True if showing within a "dialog", false if not
	this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
	this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
	this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
	this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
	this._promptClass = 'ui-datepicker-prompt'; // The name of the dialog prompt marker class
	this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
	this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[''] = { // Default regional settings
		clearText: 'Clear', // Display text for clear link
		clearStatus: 'Erase the current date', // Status text for clear link
		closeText: 'Close', // Display text for close link
		closeStatus: 'Close without change', // Status text for close link
		prevText: '&#x3c;Prev', // Display text for previous month link
		prevStatus: 'Show the previous month', // Status text for previous month link
		nextText: 'Next&#x3e;', // Display text for next month link
		nextStatus: 'Show the next month', // Status text for next month link
		currentText: 'Today', // Display text for current month link
		currentStatus: 'Show the current month', // Status text for current month link
		monthNames: ['Januar','Februar','März','April','Mai','Juni',
			'Juli','August','September','Oktober','November','Dezember'], // Names of months for drop-down and formatting
		monthNamesShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], // For formatting
		monthStatus: 'Show a different month', // Status text for selecting a month
		yearStatus: 'Show a different year', // Status text for selecting a year
		weekHeader: 'Wk', // Header for the week of the year column
		weekStatus: 'Week of the year', // Status text for the week of the year column
		dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
		dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
		dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'], // Column headings for days starting at Sunday
		dayStatus: 'Set DD as first week day', // Status text for the day of the week selection
		dateStatus: 'Select DD, M d', // Status text for the date selection
		dateFormat: 'dd.mm.yy', // See format options on parseDate
		firstDay: 1, // The first day of the week, Sun = 0, Mon = 1, ...
		initStatus: 'Select a date', // Initial Status text on opening
		isRTL: false // True if right-to-left language, false if left-to-right
	};
	this._defaults = { // Global defaults for all the date picker instances
		showOn: 'focus', // 'focus' for popup on focus,
		showAnim: null, // Name of jQuery animation for popup
		showOptions: {}, // Options for enhanced animations
		defaultDate: null, // Used when field is blank: actual date,
		appendText: '', // Display text following the input box, e.g. showing the format
		buttonText: '...', // Text for trigger button
		buttonImage: '', // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		closeAtTop: true, // True to have the clear/close at the top,
		mandatory: false, // True to hide the Clear link, false to include it
		hideIfNoPrevNext: true, // True to hide next/previous month links
		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
		gotoCurrent: false, // True if today link goes back to current selection instead
		changeMonth: true, // True if month can be selected directly, false if only prev/next
		changeYear: true, // True if year can be selected directly, false if only prev/next
		yearRange: '-10:+10', // Range of years to display in drop-down,
		changeFirstDay: true, // True to click on day name to change, false to remain as set
		highlightWeek: false, // True to highlight the selected week
		showOtherMonths: true, // True to show dates in other months, false to leave blank
		showWeeks: false, // True to show week of the year, false to omit
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
		shortYearCutoff: '+10', // Short year values < this are in the current century,
		showStatus: false, // True to show status bar at bottom, false to not show it
		statusForDate: this.dateStatus, // Function to provide status text for a date -
		minDate: null, // The earliest selectable date, or null for no limit
		maxDate: null, // The latest selectable date, or null for no limit
		duration: 'normal', // Duration of display/closure
		beforeShowDay: null, // Function that takes a date and returns an array with
		beforeShow: null, // Function that takes an input field and
    onShow: null, // Function that takes an input field and
		onSelect: null, // Define a callback function when a date is selected
		onChangeMonthYear: null, // Define a callback function when the month or year is changed
		onClose: null, // Define a callback function when the datepicker is closed
		numberOfMonths: 1, // Number of months to show at a time
		stepMonths: 1, // Number of months to step back/forward
		rangeSelect: false, // Allows for selecting a date range on one date picker
		rangeSeparator: ' - ', // Text between two dates in a range
		altField: '', // Selector for an alternate field to store selected dates into
		altFormat: '' // The date format to use for the alternate field
	};
	$.extend(this._defaults, this.regional['']);
	this.dpDiv = $('<div id="' + this._mainDivId + '" style="display: none;"></div>');
}

$.extend(Datepicker.prototype, {
	/* Class name added to elements to indicate already configured with a date picker. */
	markerClassName: 'hasDatepicker',

	/* Debug logging (if enabled). */
	log: function () {
		if (this.debug)
			console.log.apply('', arguments);
	},

	/* Override the default settings for all instances of the date picker.
	   @param  settings  object - the new settings to use as defaults (anonymous object)
	   @return the manager object */
	setDefaults: function(settings) {
		extendRemove(this._defaults, settings || {});
		return this;
	},

	/* Attach the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span
	   @param  settings  object - the new settings to use for this date picker instance (anonymous) */
	_attachDatepicker: function(target, settings) {
		var inlineSettings = null;
		for (attrName in this._defaults) {
			var attrValue = target.getAttribute('date:' + attrName);
			if (attrValue) {
				inlineSettings = inlineSettings || {};
				try {
					inlineSettings[attrName] = eval(attrValue);
				} catch (err) {
					inlineSettings[attrName] = attrValue;
				}
			}
		}
		var nodeName = target.nodeName.toLowerCase();
		var inline = (nodeName == 'div' || nodeName == 'span');
		if (!target.id)
			target.id = 'dp' + new Date().getTime();
		var inst = this._newInst($(target), inline);
		inst.settings = $.extend({}, settings || {}, inlineSettings || {});
		if (nodeName == 'input') {
			this._connectDatepicker(target, inst);
		} else if (inline) {
			this._inlineDatepicker(target, inst);
		}
	},

	/* Create a new instance object. */
	_newInst: function(target, inline) {
		return {id: target[0].id, input: target, // associated target
			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
			drawMonth: 0, drawYear: 0, // month being drawn
			inline: inline, // is datepicker inline or not
			dpDiv: (!inline ? this.dpDiv : // presentation div
			$('<div class="ui-datepicker-inline"></div>'))};
	},

	/* Attach the date picker to an input field. */
	_connectDatepicker: function(target, inst) {
		var input = $(target);
		if (input.hasClass(this.markerClassName))
			return;
		var appendText = this._get(inst, 'appendText');
		var isRTL = this._get(inst, 'isRTL');
		if (appendText)
			input[isRTL ? 'before' : 'after']('<span class="' + this._appendClass + '">' + appendText + '</span>');
		var showOn = this._get(inst, 'showOn');
		if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
			input.focus(this._showDatepicker);
		if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
			var buttonText = this._get(inst, 'buttonText');
			var buttonImage = this._get(inst, 'buttonImage');
			var trigger = $(this._get(inst, 'buttonImageOnly') ?
				$('<img/>').addClass(this._triggerClass).
					attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
				$('<button type="button"></button>').addClass(this._triggerClass).
					html(buttonImage == '' ? buttonText : $('<img/>').attr(
					{ src:buttonImage, alt:buttonText, title:buttonText })));
			input[isRTL ? 'before' : 'after'](trigger);
			trigger.click(function() {
				if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target)
					$.datepicker._hideDatepicker();
				else
					$.datepicker._showDatepicker(target);
				return false;
			});
		}
		input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).
			bind("setData.datepicker", function(event, key, value) {
				inst.settings[key] = value;
			}).bind("getData.datepicker", function(event, key) {
				return this._get(inst, key);
			});
		$.data(target, PROP_NAME, inst);
	},

	/* Attach an inline date picker to a div. */
	_inlineDatepicker: function(target, inst) {
		var input = $(target);
		if (input.hasClass(this.markerClassName))
			return;
		input.addClass(this.markerClassName).append(inst.dpDiv).
			bind("setData.datepicker", function(event, key, value){
				inst.settings[key] = value;
			}).bind("getData.datepicker", function(event, key){
				return this._get(inst, key);
			});
		$.data(target, PROP_NAME, inst);
		this._setDate(inst, this._getDefaultDate(inst));
		this._updateDatepicker(inst);
	},

	/* Pop-up the date picker in a "dialog" box.
	   @param  input     element - ignored
	   @param  dateText  string - the initial date to display (in the current format)
	   @param  onSelect  function - the function(dateText) to call when a date is selected
	   @param  settings  object - update the dialog date picker instance's settings (anonymous object)
	   @param  pos       int[2] - coordinates for the dialog's position within the screen or
	                     event - with x/y coordinates or
	                     leave empty for default (screen centre)
	   @return the manager object */
	_dialogDatepicker: function(input, dateText, onSelect, settings, pos) {
		var inst = this._dialogInst; // internal instance
		if (!inst) {
			var id = 'dp' + new Date().getTime();
			this._dialogInput = $('<input type="text" id="' + id +
				'" size="1" style="position: absolute; top: -100px;"/>');
			this._dialogInput.keydown(this._doKeyDown);
			$('body').append(this._dialogInput);
			inst = this._dialogInst = this._newInst(this._dialogInput, false);
			inst.settings = {};
			$.data(this._dialogInput[0], PROP_NAME, inst);
		}
		extendRemove(inst.settings, settings || {});
		this._dialogInput.val(dateText);

		this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
		if (!this._pos) {
			var browserWidth = window.innerWidth || document.documentElement.clientWidth ||	document.body.clientWidth;
			var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
			var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
			var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
			this._pos = // should use actual width/height below
				[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
		}

		this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px');
		inst.settings.onSelect = onSelect;
		this._inDialog = true;
		this.dpDiv.addClass(this._dialogClass);
		this._showDatepicker(this._dialogInput[0]);
		if ($.blockUI)
			$.blockUI(this.dpDiv);
		$.data(this._dialogInput[0], PROP_NAME, inst);
		return this;
	},

	/* Detach a datepicker from its control.
	   @param  target    element - the target input field or division or span */
	_destroyDatepicker: function(target) {
		var nodeName = target.nodeName.toLowerCase();
		var $target = $(target);
		$.removeData(target, PROP_NAME);
		if (nodeName == 'input') {
			$target.siblings('.' + this._appendClass).remove().end().
				siblings('.' + this._triggerClass).remove().end().
				removeClass(this.markerClassName).
				unbind('focus', this._showDatepicker).
				unbind('keydown', this._doKeyDown).
				unbind('keypress', this._doKeyPress);
		} else if (nodeName == 'div' || nodeName == 'span')
			$target.removeClass(this.markerClassName).empty();
	},

	/* Enable the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span */
	_enableDatepicker: function(target) {
		target.disabled = false;
		$(target).siblings('button.' + this._triggerClass).each(function() { this.disabled = false; }).end().
			siblings('img.' + this._triggerClass).css({opacity: '1.0', cursor: ''});
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value == target ? null : value); }); // delete entry
	},

	/* Disable the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span */
	_disableDatepicker: function(target) {
		target.disabled = true;
		$(target).siblings('button.' + this._triggerClass).each(function() { this.disabled = true; }).end().
			siblings('img.' + this._triggerClass).css({opacity: '0.5', cursor: 'default'});
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value == target ? null : value); }); // delete entry
		this._disabledInputs[this._disabledInputs.length] = target;
	},

	/* Is the first field in a jQuery collection disabled as a datepicker?
	   @param  target    element - the target input field or division or span
	   @return boolean - true if disabled, false if enabled */
	_isDisabledDatepicker: function(target) {
		if (!target)
			return false;
		for (var i = 0; i < this._disabledInputs.length; i++) {
			if (this._disabledInputs[i] == target)
				return true;
		}
		return false;
	},

	/* Update the settings for a date picker attached to an input field or division.
	   @param  target  element - the target input field or division or span
	   @param  name    object - the new settings to update or
	                   string - the name of the setting to change or
	   @param  value   any - the new value for the setting (omit if above is an object) */
	_changeDatepicker: function(target, name, value) {
		var settings = name || {};
		if (typeof name == 'string') {
			settings = {};
			settings[name] = value;
		}
		if (inst = $.data(target, PROP_NAME)) {
			extendRemove(inst.settings, settings);
			this._updateDatepicker(inst);
		}
	},

	/* Set the dates for a jQuery selection.
	   @param  target   element - the target input field or division or span
	   @param  date     Date - the new date
	   @param  endDate  Date - the new end date for a range (optional) */
	_setDateDatepicker: function(target, date, endDate) {
		var inst = $.data(target, PROP_NAME);
		if (inst) {
			this._setDate(inst, date, endDate);
			this._updateDatepicker(inst);
		}
	},

	/* Get the date(s) for the first entry in a jQuery selection.
	   @param  target  element - the target input field or division or span
	   @return Date - the current date or
	           Date[2] - the current dates for a range */
	_getDateDatepicker: function(target) {
		var inst = $.data(target, PROP_NAME);
		if (inst)
			this._setDateFromField(inst);
		return (inst ? this._getDate(inst) : null);
	},

	/* Handle keystrokes. */
	_doKeyDown: function(e) {
		var inst = $.data(e.target, PROP_NAME);
		var handled = true;
		if ($.datepicker._datepickerShowing)
			switch (e.keyCode) {
				case 9:  $.datepicker._hideDatepicker(null, '');
						break; // hide on tab out
				case 13: $.datepicker._selectDay(e.target, inst.selectedMonth, inst.selectedYear,
							$('td.ui-datepicker-days-cell-over', inst.dpDiv)[0]);
						return false; // don't submit the form
						break; // select the value on enter
				case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
						break; // hide on escape
				case 33: $.datepicker._adjustDate(e.target, (e.ctrlKey ? -1 :
							-$.datepicker._get(inst, 'stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
						break; // previous month/year on page up/+ ctrl
				case 34: $.datepicker._adjustDate(e.target, (e.ctrlKey ? +1 :
							+$.datepicker._get(inst, 'stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
						break; // next month/year on page down/+ ctrl
				case 35: if (e.ctrlKey) $.datepicker._clearDate(e.target);
						break; // clear on ctrl+end
				case 36: if (e.ctrlKey) $.datepicker._gotoToday(e.target);
						break; // current on ctrl+home
				case 37: if (e.ctrlKey) $.datepicker._adjustDate(e.target, -1, 'D');
						break; // -1 day on ctrl+left
				case 38: if (e.ctrlKey) $.datepicker._adjustDate(e.target, -7, 'D');
						break; // -1 week on ctrl+up
				case 39: if (e.ctrlKey) $.datepicker._adjustDate(e.target, +1, 'D');
						break; // +1 day on ctrl+right
				case 40: if (e.ctrlKey) $.datepicker._adjustDate(e.target, +7, 'D');
						break; // +1 week on ctrl+down
				default: handled = false;
			}
		else if (e.keyCode == 36 && e.ctrlKey) // display the date picker on ctrl+home
			$.datepicker._showDatepicker(this);
		else
			handled = false;
		if (handled) {
			e.preventDefault();
			e.stopPropagation();
		}
	},

	/* Filter entered characters - based on date format. */
	_doKeyPress: function(e) {
		var inst = $.data(e.target, PROP_NAME);
		var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
		var chr = String.fromCharCode(e.charCode == undefined ? e.keyCode : e.charCode);
		return e.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
	},

	/* Pop-up the date picker for a given input field.
	   @param  input  element - the input field attached to the date picker or
	                  event - if triggered by focus */
	_showDatepicker: function(input) {
		input = input.target || input;
		if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
			input = $('input', input.parentNode)[0];
		if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
			return;
		var inst = $.data(input, PROP_NAME);
		var beforeShow = $.datepicker._get(inst, 'beforeShow');
		extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
		$.datepicker._hideDatepicker(null, '');
		$.datepicker._lastInput = input;
		$.datepicker._setDateFromField(inst);
		if ($.datepicker._inDialog) // hide cursor
			input.value = '';
		if (!$.datepicker._pos) { // position below input
			$.datepicker._pos = $.datepicker._findPos(input);
			$.datepicker._pos[1] += input.offsetHeight; // add the height
		}
		var isFixed = false;
		$(input).parents().each(function() {
			isFixed |= $(this).css('position') == 'fixed';
			return !isFixed;
		});
		if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
			$.datepicker._pos[0] -= document.documentElement.scrollLeft;
			$.datepicker._pos[1] -= document.documentElement.scrollTop;
		}
		var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
		$.datepicker._pos = null;
		inst.rangeStart = null;
		$.datepicker._updateDatepicker(inst);
		offset = $.datepicker._checkOffset(inst, offset, isFixed);
		inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
			'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none'
    });
		if (!inst.inline) {
			var showAnim = $.datepicker._get(inst, 'showAnim') || 'show';
			var duration = $.datepicker._get(inst, 'duration');
			var postProcess = function() {
				$.datepicker._datepickerShowing = true;
				if ($.browser.msie && parseInt($.browser.version) < 7) // fix IE < 7 select problems
					$('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 25,
						height: inst.dpDiv.height() + 25});
			};
      var onShow = $.datepicker._get(inst, 'onShow');
      extendRemove(inst.settings, (onShow ? onShow.apply(input, [input, inst]) : {}));
			if ($.effects && $.effects[showAnim])
				inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
			else
				inst.dpDiv[showAnim](duration, postProcess);
			if (duration == '')
				postProcess();
			if (inst.input[0].type != 'hidden')
				inst.input[0].focus();
			$.datepicker._curInst = inst;
		}
	},
	/* Generate the date picker content. */
	_updateDatepicker: function(inst) {
		var dims = {width: inst.dpDiv.width() + 4,
			height: inst.dpDiv.height() + 4};
		inst.dpDiv.empty().append(this._generateDatepicker(inst))
		var numMonths = this._getNumberOfMonths(inst);
		inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
			'Class']('ui-datepicker-multi');
		inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
			'Class']('ui-datepicker-rtl');
		if (inst.input && inst.input[0].type != 'hidden')
			$(inst.input[0]).focus();
    var action = this._get(inst, 'afterUpdate');
    extendRemove(inst.settings, (action ? action.apply(this, [this, inst]) : {}));
	},

	/* Check positioning to remain on screen. */
	_checkOffset: function(inst, offset, isFixed) {
		var pos = inst.input ? this._findPos(inst.input[0]) : null;
		var browserWidth = window.innerWidth || document.documentElement.clientWidth;
		var browserHeight = window.innerHeight || document.documentElement.clientHeight;
		var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
		var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
		if (this._get(inst, 'isRTL') || (offset.left + inst.dpDiv.width() - scrollX) > browserWidth)
			offset.left = Math.max((isFixed ? 0 : scrollX),
				pos[0] + (inst.input ? inst.input.width() : 0) - (isFixed ? scrollX : 0) - inst.dpDiv.width() -
				(isFixed && $.browser.opera ? document.documentElement.scrollLeft : 0));
		else
			offset.left -= (isFixed ? scrollX : 0);
		if ((offset.top + inst.dpDiv.height() - scrollY) > browserHeight)
			offset.top = Math.max((isFixed ? 0 : scrollY),
				pos[1] - (isFixed ? scrollY : 0) - (this._inDialog ? 0 : inst.dpDiv.height()) -
				(isFixed && $.browser.opera ? document.documentElement.scrollTop : 0));
		else
			offset.top -= (isFixed ? scrollY : 0);
		return offset;
	},

	/* Find an object's position on the screen. */
	_findPos: function(obj) {
        while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
            obj = obj.nextSibling;
        }
        var position = $(obj).offset();
	    return [position.left, position.top];
	},

	/* Hide the date picker from view.
	   @param  input  element - the input field attached to the date picker
	   @param  duration  string - the duration over which to close the date picker */
	_hideDatepicker: function(input, duration) {
		var inst = this._curInst;
		if (!inst)
			return;
		var rangeSelect = this._get(inst, 'rangeSelect');
		this._stayOpen = false;
		if (this._datepickerShowing) {
			duration = (duration != null ? duration : this._get(inst, 'duration'));
			var showAnim = this._get(inst, 'showAnim');
			var postProcess = function() {
				$.datepicker._tidyDialog(inst);
			};
			if (duration != '' && $.effects && $.effects[showAnim])
				inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'),
					duration, postProcess);
			else
				inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' :
					(showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess);
			if (duration == '')
				this._tidyDialog(inst);
			var onClose = this._get(inst, 'onClose');
			if (onClose)
				onClose.apply((inst.input ? inst.input[0] : null),
					[this._getDate(inst), inst]);  // trigger custom callback
			this._datepickerShowing = false;
			this._lastInput = null;
			inst.settings.prompt = null;
			if (this._inDialog) {
				this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
				if ($.blockUI) {
					$.unblockUI();
					$('body').append(this.dpDiv);
				}
			}
			this._inDialog = false;
		}
		this._curInst = null;
	},

	/* Tidy up after a dialog display. */
	_tidyDialog: function(inst) {
		inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker');
		$('.' + this._promptClass, inst.dpDiv).remove();
	},

	/* Close date picker if clicked elsewhere. */
	_checkExternalClick: function(event) {

		if (!$.datepicker._curInst)
			return;
		var $target = $(event.target);
		if (($target.parents('#' + $.datepicker._mainDivId).length == 0) &&
				!$target.hasClass($.datepicker.markerClassName) &&
				!$target.hasClass($.datepicker._triggerClass) &&
				$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
			$.datepicker._hideDatepicker(null, '');
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function(id, offset, period) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		this._adjustInstDate(inst, offset, period);
		this._updateDatepicker(inst);
	},

	/* Action for current link. */
	_gotoToday: function(id) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
			inst.selectedDay = inst.currentDay;
			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
			inst.drawYear = inst.selectedYear = inst.currentYear;
		}
		else {
		var date = new Date();
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		}
		this._adjustDate(target);
		this._notifyChange(inst);
	},

	/* Action for selecting a new month/year. */
	_selectMonthYear: function(id, select, period) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		inst._selectingMonthYear = false;
		inst[period == 'M' ? 'drawMonth' : 'drawYear'] =
			select.options[select.selectedIndex].value - 0;
		this._adjustDate(target);
		this._notifyChange(inst);
	},

	/* Restore input focus after not changing month/year. */
	_clickMonthYear: function(id) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		if (inst.input && inst._selectingMonthYear && !$.browser.msie)
			inst.input[0].focus();
		inst._selectingMonthYear = !inst._selectingMonthYear;
	},

	/* Action for changing the first week day. */
	_changeFirstDay: function(id, day) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		inst.settings.firstDay = day;
		this._updateDatepicker(inst);
	},

	/* Action for selecting a day. */
	_selectDay: function(id, month, year, td) {
		if ($(td).hasClass(this._unselectableClass))
			return;
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		var rangeSelect = this._get(inst, 'rangeSelect');
		if (rangeSelect) {
			this._stayOpen = !this._stayOpen;
			if (this._stayOpen) {
				$('.ui-datepicker td').removeClass(this._currentClass);
				$(td).addClass(this._currentClass);
			}
		}
		inst.selectedDay = inst.currentDay = $('a', td).html();
		inst.selectedMonth = inst.currentMonth = month;
		inst.selectedYear = inst.currentYear = year;
		if (this._stayOpen) {
			inst.endDay = inst.endMonth = inst.endYear = null;
		}
		else if (rangeSelect) {
			inst.endDay = inst.currentDay;
			inst.endMonth = inst.currentMonth;
			inst.endYear = inst.currentYear;
		}
		this._selectDate(id, this._formatDate(inst,
			inst.currentDay, inst.currentMonth, inst.currentYear));
		if (this._stayOpen) {
			this._updateDatepicker(inst);
		}
		else if (rangeSelect) {
			inst.selectedDay = inst.currentDay = inst.rangeStart.getDate();
			inst.selectedMonth = inst.currentMonth = inst.rangeStart.getMonth();
			inst.selectedYear = inst.currentYear = inst.rangeStart.getFullYear();
			if (inst.inline)
				this._updateDatepicker(inst);
		}
	},

	/* Erase the input field and hide the date picker. */
	_clearDate: function(id) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		if (this._get(inst, 'mandatory'))
			return;
		this._stayOpen = false;
		inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null;
		this._selectDate(target, '');
	},

	/* Update the input field with the selected date. */
	_selectDate: function(id, dateStr) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
		if (this._get(inst, 'rangeSelect') && dateStr)
			dateStr = (inst.rangeStart ? this._formatDate(inst, inst.rangeStart) :
				dateStr) + this._get(inst, 'rangeSeparator') + dateStr;
		var onSelect = this._get(inst, 'onSelect');
		if (onSelect)
			onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst, this]);  // trigger custom callback
		else if (inst.input)
			inst.input.trigger('change'); // fire the change event
		if (inst.inline)
			this._updateDatepicker(inst);
		else if (!this._stayOpen) {
			this._hideDatepicker(null, this._get(inst, 'duration'));
			this._lastInput = inst.input[0];
			if (typeof(inst.input[0]) != 'object')
				inst.input[0].focus(); // restore focus
			this._lastInput = null;
		}
	},

	/* Update any alternate field to synchronise with the main field. */
	_updateAlternate: function(inst) {
		var altField = this._get(inst, 'altField');
		if (altField) { // update alternate field too
			var altFormat = this._get(inst, 'altFormat');
			var date = this._getDate(inst);
			dateStr = (isArray(date) ? (!date[0] && !date[1] ? '' :
				this.formatDate(altFormat, date[0], this._getFormatConfig(inst)) +
				this._get(inst, 'rangeSeparator') + this.formatDate(
				altFormat, date[1] || date[0], this._getFormatConfig(inst))) :
				this.formatDate(altFormat, date, this._getFormatConfig(inst)));
			$(altField).each(function() { $(this).val(dateStr); });
		}
	},

	/* Set as beforeShowDay function to prevent selection of weekends.
	   @param  date  Date - the date to customise
	   @return [boolean, string] - is this date selectable?, what is its CSS class? */
	noWeekends: function(date) {
		var day = date.getDay();
		return [(day > 0 && day < 6), ''];
	},

	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
	   @param  date  Date - the date to get the week for
	   @return  number - the number of the week within the year that contains this date */
	iso8601Week: function(date) {
		var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
		var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
		var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
		firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
		if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
			checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
			return $.datepicker.iso8601Week(checkDate);
		} else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
			firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
			if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
				checkDate.setDate(checkDate.getDate() + 3); // Generate for next year
				return $.datepicker.iso8601Week(checkDate);
			}
		}
		return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
	},

	/* Provide status text for a particular date.
	   @param  date  the date to get the status for
	   @param  inst  the current datepicker instance
	   @return  the status display text for this date */
	dateStatus: function(date, inst) {
		return $.datepicker.formatDate($.datepicker._get(inst, 'dateStatus'),
			date, $.datepicker._getFormatConfig(inst));
	},

	/* Parse a string value into a date object.
	   See formatDate below for the possible formats.

	   @param  format    string - the expected format of the date
	   @param  value     string - the date in the above format
	   @param  settings  Object - attributes include:
	                     shortYearCutoff  number - the cutoff year for determining the century (optional)
	                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)
	                     dayNames         string[7] - names of the days from Sunday (optional)
	                     monthNamesShort  string[12] - abbreviated names of the months (optional)
	                     monthNames       string[12] - names of the months (optional)
	   @return  Date - the extracted date value or null if value is blank */
	parseDate: function (format, value, settings) {
		if (format == null || value == null)
			throw 'Invalid arguments';
		value = (typeof value == 'object' ? value.toString() : value + '');
		if (value == '')
			return null;
		var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
		var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
		var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
		var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
		var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
		var year = -1;
		var month = -1;
		var day = -1;
		var literal = false;
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches)
				iFormat++;
			return matches;
		};
		var getNumber = function(match) {
			lookAhead(match);
			var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : 2));
			var size = origSize;
			var num = 0;
			while (size > 0 && iValue < value.length &&
					value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
				num = num * 10 + (value.charAt(iValue++) - 0);
				size--;
			}
			if (size == origSize)
				throw 'Missing number at position ' + iValue;
			return num;
		};
		var getName = function(match, shortNames, longNames) {
			var names = (lookAhead(match) ? longNames : shortNames);
			var size = 0;
			for (var j = 0; j < names.length; j++)
				size = Math.max(size, names[j].length);
			var name = '';
			var iInit = iValue;
			while (size > 0 && iValue < value.length) {
				name += value.charAt(iValue++);
				for (var i = 0; i < names.length; i++)
					if (name == names[i])
						return i + 1;
				size--;
			}
			throw 'Unknown name at position ' + iInit;
		};
		var checkLiteral = function() {
			if (value.charAt(iValue) != format.charAt(iFormat))
				throw 'Unexpected literal at position ' + iValue;
			iValue++;
		};
		var iValue = 0;
		for (var iFormat = 0; iFormat < format.length; iFormat++) {
			if (literal)
				if (format.charAt(iFormat) == "'" && !lookAhead("'"))
					literal = false;
				else
					checkLiteral();
			else
				switch (format.charAt(iFormat)) {
					case 'd':
						day = getNumber('d');
						break;
					case 'D':
						getName('D', dayNamesShort, dayNames);
						break;
					case 'm':
						month = getNumber('m');
						break;
					case 'M':
						month = getName('M', monthNamesShort, monthNames);
						break;
					case 'y':
						year = getNumber('y');
						break;
					case '@':
						var date = new Date(getNumber('@'));
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "'":
						if (lookAhead("'"))
							checkLiteral();
						else
							literal = true;
						break;
					default:
						checkLiteral();
				}
		}
		if (year < 100)
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
				(year <= shortYearCutoff ? 0 : -100);
		var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
		if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
			throw 'Invalid date'; // E.g. 31/02/*
		return date;
	},

	/* Standard date formats. */
	ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
	COOKIE: 'D, dd M yy',
	ISO_8601: 'yy-mm-dd',
	RFC_822: 'D, d M y',
	RFC_850: 'DD, dd-M-y',
	RFC_1036: 'D, d M y',
	RFC_1123: 'D, d M yy',
	RFC_2822: 'D, d M yy',
	RSS: 'D, d M y', // RFC 822
	TIMESTAMP: '@',
	W3C: 'yy-mm-dd', // ISO 8601

	/* Format a date object into a string value.
	   The format can be combinations of the following:
	   d  - day of month (no leading zero)
	   dd - day of month (two digit)
	   D  - day name short
	   DD - day name long
	   m  - month of year (no leading zero)
	   mm - month of year (two digit)
	   M  - month name short
	   MM - month name long
	   y  - year (two digit)
	   yy - year (four digit)
	   @ - Unix timestamp (ms since 01/01/1970)
	   '...' - literal text
	   '' - single quote

	   @param  format    string - the desired format of the date
	   @param  date      Date - the date value to format
	   @param  settings  Object - attributes include:
	                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)
	                     dayNames         string[7] - names of the days from Sunday (optional)
	                     monthNamesShort  string[12] - abbreviated names of the months (optional)
	                     monthNames       string[12] - names of the months (optional)
	   @return  string - the date in the above format */
	formatDate: function (format, date, settings) {
		if (!date)
			return '';
		var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
		var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
		var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
		var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches)
				iFormat++;
			return matches;
		};
		var formatNumber = function(match, value) {
			return (lookAhead(match) && value < 10 ? '0' : '') + value;
		};
		var formatName = function(match, value, shortNames, longNames) {
			return (lookAhead(match) ? longNames[value] : shortNames[value]);
		};
		var output = '';
		var literal = false;
		if (date)
			for (var iFormat = 0; iFormat < format.length; iFormat++) {
				if (literal)
					if (format.charAt(iFormat) == "'" && !lookAhead("'"))
						literal = false;
					else
						output += format.charAt(iFormat);
				else
					switch (format.charAt(iFormat)) {
						case 'd':
							output += formatNumber('d', date.getDate());
							break;
						case 'D':
							output += formatName('D', date.getDay(), dayNamesShort, dayNames);
							break;
						case 'm':
							output += formatNumber('m', date.getMonth() + 1);
							break;
						case 'M':
							output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
							break;
						case 'y':
							output += (lookAhead('y') ? date.getFullYear() :
								(date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
							break;
						case '@':
							output += date.getTime();
							break;
						case "'":
							if (lookAhead("'"))
								output += "'";
							else
								literal = true;
							break;
						default:
							output += format.charAt(iFormat);
					}
			}
		return output;
	},

	/* Extract all possible characters from the date format. */
	_possibleChars: function (format) {
		var chars = '';
		var literal = false;
		for (var iFormat = 0; iFormat < format.length; iFormat++)
			if (literal)
				if (format.charAt(iFormat) == "'" && !lookAhead("'"))
					literal = false;
				else
					chars += format.charAt(iFormat);
			else
				switch (format.charAt(iFormat)) {
					case 'd': case 'm': case 'y': case '@':
						chars += '0123456789';
						break;
					case 'D': case 'M':
						return null; // Accept anything
					case "'":
						if (lookAhead("'"))
							chars += "'";
						else
							literal = true;
						break;
					default:
						chars += format.charAt(iFormat);
				}
		return chars;
	},

	/* Get a setting value, defaulting if necessary. */
	_get: function(inst, name) {
		return inst.settings[name] !== undefined ?
			inst.settings[name] : this._defaults[name];
	},

	/* Parse existing date and initialise date picker. */
	_setDateFromField: function(inst) {
		var dateFormat = this._get(inst, 'dateFormat');
		var dates = inst.input ? inst.input.val().split(this._get(inst, 'rangeSeparator')) : null;
		inst.endDay = inst.endMonth = inst.endYear = null;
		var date = defaultDate = this._getDefaultDate(inst);
		if (dates.length > 0) {
			var settings = this._getFormatConfig(inst);
			if (dates.length > 1) {
				date = this.parseDate(dateFormat, dates[1], settings) || defaultDate;
				inst.endDay = date.getDate();
				inst.endMonth = date.getMonth();
				inst.endYear = date.getFullYear();
			}
			try {
				date = this.parseDate(dateFormat, dates[0], settings) || defaultDate;
			} catch (e) {
				this.log(e);
				date = defaultDate;
			}
		}
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		inst.currentDay = (dates[0] ? date.getDate() : 0);
		inst.currentMonth = (dates[0] ? date.getMonth() : 0);
		inst.currentYear = (dates[0] ? date.getFullYear() : 0);
		this._adjustInstDate(inst);
	},

	/* Retrieve the default date shown on opening. */
	_getDefaultDate: function(inst) {
    var action = this._get(inst, 'defaultDateCb');
    var def_date = (action ? action.apply(this,[this, inst]) : null);
    if (!def_date) {
      def_date = new Date();
    }
		var date = this._determineDate(this._get(inst, 'defaultDate'), def_date);
		var minDate = this._getMinMaxDate(inst, 'min', true);
		var maxDate = this._getMinMaxDate(inst, 'max');
		date = (minDate && date < minDate ? minDate : date);
		date = (maxDate && date > maxDate ? maxDate : date);
		return date;
	},

	/* A date may be specified as an exact value or a relative one. */
	_determineDate: function(date, defaultDate) {
		var offsetNumeric = function(offset) {
			var date = new Date();
			date.setDate(date.getDate() + offset);
			return date;
		};
		var offsetString = function(offset, getDaysInMonth) {
			var date = new Date();
			var year = date.getFullYear();
			var month = date.getMonth();
			var day = date.getDate();
			var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
			var matches = pattern.exec(offset);
			while (matches) {
				switch (matches[2] || 'd') {
					case 'd' : case 'D' :
						day += (matches[1] - 0); break;
					case 'w' : case 'W' :
						day += (matches[1] * 7); break;
					case 'm' : case 'M' :
						month += (matches[1] - 0);
						day = Math.min(day, getDaysInMonth(year, month));
						break;
					case 'y': case 'Y' :
						year += (matches[1] - 0);
						day = Math.min(day, getDaysInMonth(year, month));
						break;
				}
				matches = pattern.exec(offset);
			}
			return new Date(year, month, day);
		};
		date = (date == null ? defaultDate :
			(typeof date == 'string' ? offsetString(date, this._getDaysInMonth) :
			(typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date)));
		date = (date && date.toString() == 'Invalid Date' ? defaultDate : date);
		if (date) {
			date.setHours(0);
			date.setMinutes(0);
			date.setSeconds(0);
			date.setMilliseconds(0);
		}
		return this._daylightSavingAdjust(date);
	},

	/* Handle switch to/from daylight saving.
	   Hours may be non-zero on daylight saving cut-over:
	   > 12 when midnight changeover, but then cannot generate
	   midnight datetime, so jump to 1AM, otherwise reset.
	   @param  date  (Date) the date to check
	   @return  (Date) the corrected date */
	_daylightSavingAdjust: function(date) {
		if (!date) return null;
		date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
		return date;
	},

	/* Set the date(s) directly. */
	_setDate: function(inst, date, endDate) {
		var clear = !(date);
		date = this._determineDate(date, new Date());
		inst.selectedDay = inst.currentDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();
		if (this._get(inst, 'rangeSelect')) {
			if (endDate) {
				endDate = this._determineDate(endDate, null);
				inst.endDay = endDate.getDate();
				inst.endMonth = endDate.getMonth();
				inst.endYear = endDate.getFullYear();
			} else {
				inst.endDay = inst.currentDay;
				inst.endMonth = inst.currentMonth;
				inst.endYear = inst.currentYear;
			}
		}
		this._adjustInstDate(inst);
		if (inst.input)
			inst.input.val(clear ? '' : this._formatDate(inst) +
				(!this._get(inst, 'rangeSelect') ? '' : this._get(inst, 'rangeSeparator') +
				this._formatDate(inst, inst.endDay, inst.endMonth, inst.endYear)));
	},

	/* Retrieve the date(s) directly. */
	_getDate: function(inst) {
		var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
			this._daylightSavingAdjust(new Date(
			inst.currentYear, inst.currentMonth, inst.currentDay)));
		if (this._get(inst, 'rangeSelect')) {
			return [inst.rangeStart || startDate,
				(!inst.endYear ? inst.rangeStart || startDate :
				this._daylightSavingAdjust(new Date(inst.endYear, inst.endMonth, inst.endDay)))];
		} else
			return startDate;
	},

	/* Generate the HTML for the current state of the date picker. */
	_generateDatepicker: function(inst) {
		var today = new Date();
		today = this._daylightSavingAdjust(
			new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
		var showStatus = this._get(inst, 'showStasetus');
		var isRTL = this._get(inst, 'isRTL');
		var clear = (this._get(inst, 'mandatory') ? '' :
			'<div class="ui-datepicker-clear"><a onclick="jQuery.datepicker._clearDate(\'#' + inst.id + '\');"' +
			(showStatus ? this._addStatus(inst, this._get(inst, 'clearStatus') || '&#xa0;') : '') + '>' +
			this._get(inst, 'clearText') + '</a></div>');
		var controls = '<div class="ui-datepicker-control">' + (isRTL ? '' : clear) +
			'<div class="ui-datepicker-close"><a onclick="jQuery.datepicker._hideDatepicker();"' +
			(showStatus ? this._addStatus(inst, this._get(inst, 'closeStatus') || '&#xa0;') : '') + '>' +
			this._get(inst, 'closeText') + '</a></div>' + (isRTL ? clear : '')  + '</div>';
		var prompt = this._get(inst, 'prompt');
		var closeAtTop = this._get(inst, 'closeAtTop');
		var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
		var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
		var numMonths = this._getNumberOfMonths(inst);
		var stepMonths = this._get(inst, 'stepMonths');
		var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
		var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
			new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
		var minDate = this._getMinMaxDate(inst, 'min', true);
		var maxDate = this._getMinMaxDate(inst, 'max');
		var drawMonth = inst.drawMonth;
		var drawYear = inst.drawYear;
		if (maxDate) {
			var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
				maxDate.getMonth() - numMonths[1] + 1, maxDate.getDate()));
			maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
			while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
				drawMonth--;
				if (drawMonth < 0) {
					drawMonth = 11;
					drawYear--;
				}
			}
		}
    var prev = "";
    if (this._canAdjustMonth(inst, -1, drawYear, drawMonth)) {
      var prev = "";
      var prevText = this._get(inst, 'prevText');
      prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
        this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
        this._getFormatConfig(inst)));
      prev = '<div class="ui-datepicker-prev">' + (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
        '<a onclick="jQuery.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
        (showStatus ? this._addStatus(inst, this._get(inst, 'prevStatus') || '&#xa0;') : '') + '>' + prevText + '</a>' :
        (hideIfNoPrevNext ? '' : '<label>' + prevText + '</label>')) + '</div>';
    }
    var next = "";
    if (this._canAdjustMonth(inst, +1, drawYear, drawMonth)) {
      var nextText = this._get(inst, 'nextText');
      nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
        this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
        this._getFormatConfig(inst)));
      next = '<div class="ui-datepicker-next">' + (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
        '<a onclick="jQuery.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
        (showStatus ? this._addStatus(inst, this._get(inst, 'nextStatus') || '&#xa0;') : '') + '>' + nextText + '</a>' :
        (hideIfNoPrevNext ? '' : '<label>' + nextText + '</label>')) + '</div>';
    }
		var currentText = this._get(inst, 'currentText');
		currentText = (!navigationAsDateFormat ? currentText: this.formatDate(
			currentText, today, this._getFormatConfig(inst)));
		var html = (prompt ? '<div class="' + this._promptClass + '">' + prompt + '</div>' : '') +
			(closeAtTop && !inst.inline ? controls : '') +
			'<div class="ui-datepicker-links">' + (isRTL ? next : prev) +
			(this._isInRange(inst, (this._get(inst, 'gotoCurrent') && inst.currentDay ?
			currentDate : today)) ? '<div class="ui-datepicker-current">' +
			'<a onclick="jQuery.datepicker._gotoToday(\'#' + inst.id + '\');"' +
			(showStatus ? this._addStatus(inst, this._get(inst, 'currentStatus') || '&#xa0;') : '') + '>' +
			currentText + '</a></div>' : '') + (isRTL ? prev : next) + '</div>';
		var firstDay = this._get(inst, 'firstDay');
		var changeFirstDay = this._get(inst, 'changeFirstDay');
		var dayNames = this._get(inst, 'dayNames');
		var dayNamesShort = this._get(inst, 'dayNamesShort');
		var dayNamesMin = this._get(inst, 'dayNamesMin');
		var monthNames = this._get(inst, 'monthNames');
		var beforeShowDay = this._get(inst, 'beforeShowDay');
		var highlightWeek = this._get(inst, 'highlightWeek');
		var showOtherMonths = this._get(inst, 'showOtherMonths');
		var showWeeks = this._get(inst, 'showWeeks');
		var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
		var status = (showStatus ? this._get(inst, 'dayStatus') || '&#xa0;' : '');
		var dateStatus = this._get(inst, 'statusForDate') || this.dateStatus;
		var endDate = inst.endDay ? this._daylightSavingAdjust(
			new Date(inst.endYear, inst.endMonth, inst.endDay)) : currentDate;
		for (var row = 0; row < numMonths[0]; row++)
			for (var col = 0; col < numMonths[1]; col++) {
				var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
				html += '<div class="ui-datepicker-one-month' + (col == 0 ? ' ui-datepicker-new-row' : '') + '">' +
					this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
					selectedDate, row > 0 || col > 0, showStatus, monthNames) + // draw month headers
					'<table class="ui-datepicker" cellpadding="0" cellspacing="0"><thead>' +
					'<tr class="ui-datepicker-title-row">' +
					(showWeeks ? '<td>' + this._get(inst, 'weekHeader') + '</td>' : '');
				for (var dow = 0; dow < 7; dow++) { // days of the week
					var day = (dow + firstDay) % 7;
					var dayStatus = (status.indexOf('DD') > -1 ? status.replace(/DD/, dayNames[day]) :
						status.replace(/D/, dayNamesShort[day]));
					html += '<td' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end-cell"' : '') + '>' +
						(!changeFirstDay ? '<span' :
						'<a onclick="jQuery.datepicker._changeFirstDay(\'#' + inst.id + '\', ' + day + ');"') +
						(showStatus ? this._addStatus(inst, dayStatus) : '') + ' title="' + dayNames[day] + '">' +
						dayNamesMin[day] + (changeFirstDay ? '</a>' : '</span>') + '</td>';
				}
				html += '</tr></thead><tbody>';
				var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
				if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
					inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
				var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
				var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
				var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
				for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
					html += '<tr class="ui-datepicker-days-row">' +
						(showWeeks ? '<td class="ui-datepicker-week-col">' + calculateWeek(printDate) + '</td>' : '');
					for (var dow = 0; dow < 7; dow++) { // create date picker days
						var daySettings = (beforeShowDay ?
							beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate, inst]) : [true, '']);
						var otherMonth = (printDate.getMonth() != drawMonth);
						var unselectable = otherMonth || !daySettings[0] ||
							(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
						html += '<td class="ui-datepicker-days-cell' +
							((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end-cell' : '') + // highlight weekends
							(otherMonth ? ' ui-datepicker-otherMonth' : '') + // highlight days from other months
							(printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth ?
							' ui-datepicker-days-cell-over' : '') + // highlight selected day
							(unselectable ? ' ' + this._unselectableClass : '') +  // highlight unselectable days
							(otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
							(printDate.getTime() >= currentDate.getTime() && printDate.getTime() <= endDate.getTime() ?  // in current range
							' ' + this._currentClass : '') + // highlight selected day
							(printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
							((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
							(unselectable ? (highlightWeek ? ' onmouseover="jQuery(this).parent().addClass(\'ui-datepicker-week-over\');"' + // highlight selection week
							' onmouseout="jQuery(this).parent().removeClass(\'ui-datepicker-week-over\');"' : '') : // unhighlight selection week
							' onmouseover="jQuery(this).addClass(\'ui-datepicker-days-cell-over\')' + // highlight selection
							(highlightWeek ? '.parent().addClass(\'ui-datepicker-week-over\')' : '') + ';' + // highlight selection week
							(!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#ui-datepicker-status-' +
							inst.id + '\').html(\'' + (dateStatus.apply((inst.input ? inst.input[0] : null),
							[printDate, inst]) || '&#xa0;') +'\');') + '"' +
							' onmouseout="jQuery(this).removeClass(\'ui-datepicker-days-cell-over\')' + // unhighlight selection
							(highlightWeek ? '.parent().removeClass(\'ui-datepicker-week-over\')' : '') + ';' + // unhighlight selection week
							(!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#ui-datepicker-status-' +
							inst.id + '\').html(\'&#xa0;\');') + '" onclick="jQuery.datepicker._selectDay(\'#' +
							inst.id + '\',' + drawMonth + ',' + drawYear + ', this);"') + '>' + // actions
							(otherMonth ? (showOtherMonths ? printDate.getDate() : '&#xa0;') : // display for other months
							(unselectable ? printDate.getDate() : '<a>' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
						printDate.setDate(printDate.getDate() + 1);
						printDate = this._daylightSavingAdjust(printDate);
					}
					html += '</tr>';
				}
				drawMonth++;
				if (drawMonth > 11) {
					drawMonth = 0;
					drawYear++;
				}
				html += '</tbody></table></div>';
			}
      var tempZ = 'javascript:false;';
		html += (showStatus ? '<div style="clear: both;"></div><div id="ui-datepicker-status-' + inst.id +
			'" class="ui-datepicker-status">' + (this._get(inst, 'initStatus') || '&#xa0;') + '</div>' : '') +
			(!closeAtTop && !inst.inline ? controls : '') +
			'<div style="clear: both; padding-bottom: 6px;"></div>' +
      '<div id="datepicker-bottom"></div>' +
			($.browser.msie && parseInt($.browser.version) < 7 && !inst.inline ?
			'<iframe style="filter:alpha(opacity=0);" src="javascript:false;" frameborder="0", scrolling="no" class="ui-datepicker-cover"></iframe>' : '');
		return html;
	},

	/* Generate the month and year header. */
	_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
			selectedDate, secondary, showStatus, monthNames) {
		minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate);
		var html = '<div class="ui-datepicker-header">';
  	html += monthNames[drawMonth] + '&#xa0;';
	  html += drawYear;
		html += '</div>'; // Close datepicker_header
		return html;
	},

	/* Provide code to set and clear the status panel. */
	_addStatus: function(inst, text) {
		return ' onmouseover="jQuery(\'#ui-datepicker-status-' + inst.id + '\').html(\'' + text + '\');" ' +
			'onmouseout="jQuery(\'#ui-datepicker-status-' + inst.id + '\').html(\'&#xa0;\');"';
	},

	/* Adjust one of the date sub-fields. */
	_adjustInstDate: function(inst, offset, period) {
		var year = inst.drawYear + (period == 'Y' ? offset : 0);
		var month = inst.drawMonth + (period == 'M' ? offset : 0);
		var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
			(period == 'D' ? offset : 0);
		var date = this._daylightSavingAdjust(new Date(year, month, day));
		var minDate = this._getMinMaxDate(inst, 'min', true);
		var maxDate = this._getMinMaxDate(inst, 'max');
		date = (minDate && date < minDate ? minDate : date);
		date = (maxDate && date > maxDate ? maxDate : date);
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		if (period == 'M' || period == 'Y')
			this._notifyChange(inst);
	},

	/* Notify change of month/year. */
	_notifyChange: function(inst) {
		var onChange = this._get(inst, 'onChangeMonthYear');
		if (onChange)
			onChange.apply((inst.input ? inst.input[0] : null),
				[new Date(inst.selectedYear, inst.selectedMonth, 1), inst]);
	},

	/* Determine the number of months to show. */
	_getNumberOfMonths: function(inst) {
		var numMonths = this._get(inst, 'numberOfMonths');
		return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
	},

	/* Determine the current maximum date - ensure no time components are set - may be overridden for a range. */
	_getMinMaxDate: function(inst, minMax, checkRange) {
		var date = this._determineDate(this._get(inst, minMax + 'Date'), null);
		return (!checkRange || !inst.rangeStart ? date :
			(!date || inst.rangeStart > date ? inst.rangeStart : date));
	},

	/* Find the number of days in a given month. */
	_getDaysInMonth: function(year, month) {
		return 32 - new Date(year, month, 32).getDate();
	},

	/* Find the day of the week of the first of a month. */
	_getFirstDayOfMonth: function(year, month) {
		return new Date(year, month, 1).getDay();
	},

	/* Determines if we should allow a "next/prev" month display change. */
	_canAdjustMonth: function(inst, offset, curYear, curMonth) {
		var numMonths = this._getNumberOfMonths(inst);
		var date = this._daylightSavingAdjust(new Date(
			curYear, curMonth + (offset < 0 ? offset : numMonths[1]), 1));
		if (offset < 0)
			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
		return this._isInRange(inst, date);
	},

	/* Is the given date in the accepted range? */
	_isInRange: function(inst, date) {
		var newMinDate = (!inst.rangeStart ? null : this._daylightSavingAdjust(
			new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)));
		newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate);
		var minDate = newMinDate || this._getMinMaxDate(inst, 'min');
		var maxDate = this._getMinMaxDate(inst, 'max');
		return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
	},

	/* Provide the configuration settings for formatting/parsing. */
	_getFormatConfig: function(inst) {
		var shortYearCutoff = this._get(inst, 'shortYearCutoff');
		shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
			new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
		return {shortYearCutoff: shortYearCutoff,
			dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
			monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
	},

	/* Format the given date for display. */
	_formatDate: function(inst, day, month, year) {
		if (!day) {
			inst.currentDay = inst.selectedDay;
			inst.currentMonth = inst.selectedMonth;
			inst.currentYear = inst.selectedYear;
		}
		var date = (day ? (typeof day == 'object' ? day :
			this._daylightSavingAdjust(new Date(year, month, day))) :
			this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
		return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
	}
});

/* jQuery extend now ignores nulls! */
function extendRemove(target, props) {
	$.extend(target, props);
	for (var name in props)
		if (props[name] == null || props[name] == undefined)
			target[name] = props[name];
	return target;
};

/* Determine whether an object is an array. */
function isArray(a) {
	return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
		(a.constructor && a.constructor.toString().match(/\Array\(\)/))));
};

/* Invoke the datepicker functionality.
   @param  options  string - a command, optionally followed by additional parameters or
                    Object - settings for attaching new datepicker functionality
   @return  jQuery object */
$.fn.datepicker = function(options){
	var otherArgs = Array.prototype.slice.call(arguments, 1);
	if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate'))
		return $.datepicker['_' + options + 'Datepicker'].
			apply($.datepicker, [this[0]].concat(otherArgs));
	return this.each(function() {
		typeof options == 'string' ?
			$.datepicker['_' + options + 'Datepicker'].
				apply($.datepicker, [this].concat(otherArgs)) :
			$.datepicker._attachDatepicker(this, options);
	});
};

$.datepicker = new Datepicker(); // singleton instance

/* Initialise the date picker. */
$(document).bind("calendar_ready", function() {
	$("#searchengine").append($.datepicker.dpDiv)//.
});
})(jQuery);


SearchMask.CalendarController = new JS.Class({
  type: "",
  initialize: function() {
    this.events_registered = false;
    this.is_shown = false;
    this.selector = "#calendar";
  },
  init: function(parent_controller) {
    var self = this;
    this.type = parent_controller.type;
    this.parent_controller = parent_controller;

    SM.DateMap.find_by_state();
    var default_entry = SM.DateRange.calendar_default_entry();
    $(this.selector).datepicker({
      numberOfMonths: 3,
      duration: '',
      dontHideByExternal: true,
      rangeSelect: true,
      minDate: default_entry.outgoing_date,
      maxDate: default_entry.return_date,
      onClose: function(x, inst) {
        var sel_date = new Date(inst.drawYear, inst.drawMonth, 1);
        SearchMask.DateMap.selected_date = sel_date;
      },
      defaultDateCb: function(obj, inst) {
        var retVal = null;
        if (SearchMask.DateMap.selected_date) {
          retVal = SearchMask.DateMap.selected_date;
        }
        return retVal;
      },
      onSelect: function(dates, inst, object) {
        object._stayOpen = true;
        var start_date = new Date(inst.selectedYear, inst.selectedMonth,
                                  inst.selectedDay,12,0,0);

        var default_start_date = SM.DateRange.default_entry().outgoing_date;
        if(start_date && (start_date < default_start_date)) {
          self.show_wrong_outgoing_date_message();
          return;
        }else{
          SearchMask.DateMap.add_date(start_date);
        }
      },
      beforeShow: function(i, inst) {
        $("#calendar_addition").show();
      },
      beforeShowDay: function(date, inst) {
        var rt = [true, ""];
        var holiday = SearchMask.DateMap.is_holiday(date.valueOf());
        if (holiday) {
          rt[1] = holiday.css_class_name;
          rt.push(holiday.describe());
        }
        if (SearchMask.DateMap.start_date() && SearchMask.DateMap.end_date()) {
          if ((date >= SearchMask.DateMap.start_date()) &&
              (date <= SearchMask.DateMap.end_date())) {
            rt[1] = rt[1] + " ui-datepicker-selected-day";
          }
        }
        return rt;
      },
      afterUpdate: function(picker, inst) {
        var bottom = $(Jaml.render("searchmask_calendar",self.type));
        var selected = SearchMask.DateMap.selected;
        bottom.find("#state_chooser").val(selected);
        bottom.find("#outgoing_label").html(
          SearchMask.DateMap.start_date_str());
        bottom.find("#return_label").html(
          SearchMask.DateMap.end_date_str());
        bottom.appendTo(inst.dpDiv);
        self.chooser_events();
        self.in_calendar_events();
        $.each(["outgoing", "return"], function(i, s) {
          $("#"+s+"_label").parent().removeClass("focus");
          if ((SearchMask.DateMap.dates.length % 2) == i) {
            $("#"+s+"_label").parent().addClass("focus");
          }
        });
      }
    });
    self.calendar_events();
  },
  setup: function(calendar) {
    this.calendar = calendar;
  },
  reset: function() {
  },
  chooser_events: function() {
    $("#state_chooser").change(function() {
      SearchMask.DateMap.find_by_state($(this).val());
      SearchMask.DateMap.selected = $(this).val();
      $("#calendar").datepicker("hide");
      $("#calendar").datepicker("show");
    });
  },
  in_calendar_events: function() {
    var self = this;
    $("#closepopup, #calendar_reset").click(function(event) {
      $("#calendar").datepicker("hide");
      self.reset();
    });
    $("#calendar_ok").click(function() {
      $("#calendar").datepicker("hide");
      $("#outgoing").val(SearchMask.DateMap.start_date_str());
      $("#return").val(SearchMask.DateMap.end_date_str()).change();

    });
  },
  calendar_events: function() {
    if (!this.events_registered) {
      var self = this;
      $("#outgoing, #return, .butsh_calendar").click(function () {
          $(self.selector).datepicker("show");
        });
      this.events_registered = true;
    }
  },
  show_wrong_outgoing_date_message: function() {
    var tmpl = 'calendar_wrong_outgoing_date';
    this.parent_controller.info_controller.info_with_template(tmpl);
  }
});
SearchMask.ChildrenController = new JS.Class({
  initialize: function() {
    this.events_registered = false;
  },

  children: function(caller) {
    this.caller = caller;
    $('#childrenbox_pos').show();
    var ele = caller.form_state.form_element;
    caller.form_state.travelers.put_children_to_form(ele);
    this.children_events();
  },
  children_at_startup: function(form_state) {
    form_state.travelers.put_children_to_form(form_state.form_element);
    this.update_children_text(form_state, true);
  },
  children_close_event: function() {
    this.update_children_text(this.caller.form_state);
    $('#childrenbox_pos').hide();
  },
  children_events: function() {
    if (!this.events_registered) {
      var self = this;
      $('#childrenbox_pos span.s_closepopup').click(function() {
        $('#child_1').val(-1);
        $('#child_2').val(-1);
        $('#child_3').val(-1);
        self.children_close_event.call(self);
        $('#more_text').hide();
      });
      $('#childrenbox_pos input[type="button"]').click(function() {
        self.children_close_event.call(self);
      });
      $('#more_children').click(function(){
        $('#more_text').show();
      });
      this.events_registered = true;
    }
  },
  update_children_text: function(formstate, no_update) {
    if (no_update !== true) {
      formstate.get_one(SearchMask.Travelers);
    }
    var children_set = formstate.travelers.children_with_age.length > 0;
    $('#child').attr('checked', children_set);
    if(children_set) {
      $('#children_number').empty();
      $('#children_number').append(
        Jaml.render("searchmask_children_info_text",
          {obj: formstate.travelers.children_with_age}).replace(/\n/g,""));
      $('#children_number').show();
    } else {
      $('#children_number').empty();
      $('#children_number').hide();
    }
  }
});
SearchMask.CommonMixin = new JS.Module({
  common_data: function(form_state_type) {
    this.childrenbox = new SearchMask.Infobox("childrenbox");
    this.childrenbox.render_template('searchmask_children');
    this.airportbox = new SearchMask.Infobox("airportbox");
    this.airportbox.render_template('searchmask_airports_map');
    this.form_state = new form_state_type($('#searchcontainer form'));
    this.form_state.set_from_url_and_cookie_and_start_params();
    this.form_state.put();
    this.children_controller = new SearchMask.ChildrenController();
    this.children_controller.children_at_startup(this.form_state);

    this.info_controller = new SearchMask.InfoController();
    this.common_events();

    $('#searchcontainer input#price').numeric();

    this.calendar_controller = new SearchMask.CalendarController();
    this.calendar_controller.init(this);
    $(document).trigger("calendar_ready");

  },
  common_events: function() {
    var self = this;
    $("#searchcontainer form").submit(function() {
      return false;
    });
    $("#more").click(function(){
      $("#row2").show();
      $("#row3").show();
      $("#more").hide();
      $("#less").show();
    });
    $("#less").click(function(){
      $("#row2").hide();
      $("#row3").hide();
      $("#less").hide();
      $("#more").show();
    });
    $("#child").click(function() {
      $('#child').attr('checked', true);
      self.children_controller.children(self);
    });
    $("#children_number").click(function(){
      $('#child').attr('checked', true);
      self.children_controller.children(self);
    });
    $('#searchcontainer input.search[type="button"]').click(function() {
      self.search();
    });
    $(this.form_state).bind('travelers_too_many_adults', function() {
      self.info_controller.info_with_template('travelers_too_many_adults');
    });
    $('#searchcontainer #traveler').change(function () {
      self.form_state.get_one(SearchMask.Travelers);
      self.form_state.validate_travelers();
    });

    $('#searchcontainer #outgoing, #searchcontainer #return').change(function(){
      self.form_state.get();
      self.form_state.validate_date_range();
    });
    $('#outgoing').change();
  },
  search: function() {
    this.form_state.get();
    location.href = this.form_state.to_url();
  },
  render: function() {
    SearchMask.FastSearchController.fast_search();
    $("#searchcontainer").empty();
  }
});

SearchMask.EarthController = new JS.Singleton({
  include: SearchMask.CommonMixin,
  type: "earth",
  index: function() {
    this.render();
    this.common_data(SearchMask.EarthFormState);
    this.earth_events();
    $(document).trigger("earth_ready");
  },
  render: function() {
    this.callSuper();
    $("#searchcontainer").append(Jaml.render("searchmask_earth"));
  },
  earth_events: function() {
    var self = this;
    $(SearchMask.Theme.element_selector).change(function(event) {
      var fs = self.form_state;
      fs.get_one(SearchMask.Theme);
      fs.setup_autocompleter(fs.theme.associated_countries());
      fs.destination_autocompleter.set_by_form_state(fs);
    });
  }
});
SearchMask.FastSearchController = new JS.Singleton({

  fast_search: function() {
    if($("#fast_search:empty").length == 1) {
      $("#fast_search").append(Jaml.render("searchmask_fast_search"));
      this.fast_search_events();
    }
  },
  fast_search_events: function() {
    $("#lastminute, #pauschal").click(function() {
      if($('#departure_airport_status').length <= 0) {
        SearchMask.LastminuteController.index();
      }
    });
    $("#hotels").click(function() {
      SearchMask.EarthController.index();
    });
    $("#flights").click(function() {
      location.href = "http://www.nix-wie-weg.de/fluege.html";
    });
    $("#fewo").click(function() {
      location.href = "http://www.nix-wie-weg.de/ferienwohnung.html";
    });
  }
});
SearchMask.InfoController = new JS.Class({
  initialize: function(){
    this.infobox = new SearchMask.Infobox();
    this.events_registered = false;
  },
  info: function(content){
    this.infobox.show(content);
    this.info_events();
  },
  info_with_template: function(tmpl){
    this.infobox.show_template(tmpl);
    this.info_events();
  },
  info_events: function() {
    if(!this.events_registered) {
      $('#infobox_pos span.s_closepopup').click(function() {
        $('#infobox_pos').hide();
      });
      this.events_registered = true;
    }
  }
});

SearchMask.LastminuteController = new JS.Singleton({
  include: SearchMask.CommonMixin,
  type: "lastminute",
  index: function() {
    this.render();
    this.common_data(SearchMask.LastminuteFormState);
    this.lastminute_events();

    SearchMask.AirportController.update_airport_status_text(this.form_state);
  },
  render: function() {
    this.callSuper();
    $("#searchcontainer").append(Jaml.render("searchmask_lastminute"));
  },
  lastminute_events: function() {
    var self = this;
    $('#airport_selector_img, #departure_airport_status').click(function() {
      SearchMask.AirportController.events_registered = false;
      SearchMask.AirportController.airport(self);
    });
  }
});
Jaml.register("checkbox", function(data) {
  input({"id": data.id,
         "name": data.id,
         "type": "checkbox",
         "value": data.value,
         "tabindex": data.index}
  );
});

Jaml.register("label", function(data) {
  label({"for": data.id}, data.txt);
});
Jaml.register('option', function(data) {
  option({value: data.value}, h(data.name));
});
Jaml.register("select", function(data) {
  select(
    $.extend({"id": data.id,
              "name": data.id,
              "tabindex": data.index},
             data.options),
    data.sel_opt
  );
});
Jaml.register("textbox", function(data) {
  input(
    $.extend(
      {"id": data.id,
       "name": data.id,
       "tabindex": data.index,
       "type": "text"},
      data.options)
  );
});

Jaml.register("searchmask_airports_buttons", function() {
  function cb(name, value) {
    var id = 'airport_' + value;
    input({type: 'checkbox', name: h(name), value: value, id: id});
  }
  function cb_lbl(name, value, p_style) {
    var id = 'airport_' + value;
    div({'id': "d_"+id, 'style': p_style},
      input({type: 'checkbox', name: h(name), value: value, id: id}),
      label({'for': id},
        span( {"class": "s_mapoff",
               'id': 'img_'+id,
               'title': h(name)} ),
        span({"class": "text"}, h(name))
      )
    );
  }

  var A = SearchMask.DepartureAirport;
  var de = A.find_default_entry();
  cb_lbl(h(de.name), de.value);

  $.each(A.find_all_virtual_entries(), function(index, virtual) {
    cb_lbl(h(virtual.name), virtual.value);
  });

  $.each(A.find_all_real_entries(), function(index, airport) {
    var style = 'left:' + airport.pos_x  + 'px;top:' + airport.pos_y  + 'px;';
    cb_lbl(h(airport.name), airport.value, style);
  });
});
Jaml.register("searchmask_airports_map", function() {
  div({"id": "map"},
    Jaml.render("searchmask_airports_buttons"),
    input(
      {"class":"ok",
       "type": "button",
       "value": "Übernehmen"}
    )
  );
});
Jaml.register("searchmask_calendar", function(type) {
  var labels = [];
  if (type != "earth") {
    labels = ["Frühester Hinflug", "Spätester Rückflug"];
  }
  else {
    labels = ["Früheste Anreise", "Späteste Abreise"];
  }
  span(
    div({"id": "calendar_topline"},
      span({"id": "closepopup", "class":"s_closepopup"})
    ),
    table({id: "calendar_addition"},
      tr(
        td({"id": "traveldates"},
          p(
            span({"class":"info"}, labels[0]+":"),
            span({id: "outgoing_label"})
          ),
          p(
            span({"class":"info"}, labels[1]+":"),
            span({id: "return_label"})
          )
        ),
        td({id: "holidays"},
          p("Ferientermine:"),
          select(
            {id: "state_chooser"},
            Jaml.render("searchmask_calendar_state",
              SM.State.all_states_with_misc())
          )
        ),
        td({"id": "buttons"},
          span({id:"calendar_reset"},"abbrechen"),
          input({"type": "button", "id": "calendar_ok", "value": "Übernehmen"})
        )
      )
    )
  );
});
Jaml.register("searchmask_calendar_state", function(object) {
  if(object.type === "country"){
    optgroup({"label": h(object.name.toString())});
  }else{
    option({"value": object.get_value()}, h(object.name.toString()));
  }
});
Jaml.register("calendar_wrong_outgoing_date", function() {
  div(
    p('Für Angebote mit Abflug in den nächsten 3 Tagen bitte ' +
      'anrufen oder mailen:'
    ),
    Jaml.render("infobox_footer")
  );
});
Jaml.register("searchmask_children", function() {
  p(
    strong("Alter bei Urlaubsbeginn:")
  );
  div({"id": "child1"},
    label({"for": "child_1"}, "1. Kind:"),
    select({"id": "child_1"},
           Jaml.render("searchmask_children_age",
                       SearchMask.Travelers.find_all_children_ages()))
  );
  div({"id": "child2"},
    label({"for": "child_2"}, "2. Kind:"),
    select({"id": "child_2"},
           Jaml.render("searchmask_children_age",
                       SearchMask.Travelers.find_all_children_ages()))
  );
  div({"id": "child3"},
    label({"for": "child_3"}, "3. Kind:"),
    select({"id": "child_3"},
           Jaml.render("searchmask_children_age",
                       SearchMask.Travelers.find_all_children_ages()))
  );
  div({"class": "clear"});
  div({"id": "more_children"},
    "+ weitere Kinder"
  );
  div({"id": "more_text", "style": "display: none;"},
    p(
      strong("Online sind max. 3 Kinder möglich.")
    ),
    p(
      a({"href" : "/mitarbeiter.html", "class": "custom"}, "Wir"),
    "helfen aber gerne persönlich: "
    ),
    Jaml.render("infobox_footer")
  );
  p({"class":"right"},
    input(
      {"class":"ok right",
       "type": "button",
       "value": "Übernehmen"}
    )
  );
});
Jaml.register("searchmask_children_age", function(object) {
  option({"value": object.value}, object.name);
});


Jaml.register("searchmask_children_info_text", function(children_array) {
  span("(");
  span({"id": "children_ages", "class": "ages"},
        children_array.obj.join(", ") + " Jahre");
  span(")");
});
Jaml.register("searchmask_earth", function() {

  var theme_data = $.map(SearchMask.Theme.find_all(), function(data) {
    return { value: data.id, name: data.name };
  });

  form({action: "", autocomplete: "off"},
    div({"id": "pos"},
    div({"id": "searchengine"},
      input({id: "calendar", type: "hidden"}),
      div({"id": "row1"},
        ul(
          li(
            ul(
              li({"class": "theme"},
                label({"for":"theme_id"}, "Thema:"),
                select({id: "theme_id", "name": "theme_id", "tabindex": "1"},
                  Jaml.render('option', theme_data)
                )
              ),
              Jaml.render("destination_part", 2),
              Jaml.render("operator_part",
                {tabindex: 3, data: SearchMask.Operator.find_lastminute()}
              )
            )
          ),
          li(
            ul(
              Jaml.render("outgoing_part", {tabindex:4,
                                            caption: "Früheste Anreise"}),
              Jaml.render("return_part",   {tabindex:5,
                                            caption: "Späteste Abreise"}),
              Jaml.render("duration_part",
                {tabindex: 6, data: SearchMask.Duration.find_earth()}
              )
            ),
            li(
              ul(
                Jaml.render("traveler_part",
                  {tabindex: 7, data: SearchMask.Travelers.find_all()}),
                Jaml.render("children_part", 8),
                Jaml.render("search_open_part", 9)
              )
            )
          )
        ),
        div({"class":"clear"})
      ),
      div({"id": "row2", "style": "display: none"},
        ul(
          li(
            Jaml.render("category_part", 10)
          ),
          li(
            ul(
              Jaml.render("accomodation_type_part", {tabindex: 20}),
              Jaml.render("catering_part",
                {tabindex: 21, data: SearchMask.Catering.find_all()}),
              Jaml.render("price_part")
            )
          ),
          li(
            ul(
              li(textbox_with_label("hotel_name", "Hotelname:", 23, {})),
              li(),
              Jaml.render("search_close_part", 24)
            )
          )
        ),
        div({"class": "clear"})
      ),
      Jaml.render('infobox')
    )
    )
  );
});
Jaml.register("searchmask_fast_search", function() {
  form({"action": "", "autocomplete": "off"},
    input(
      {"id": "lastminute",
       "name": "choice",
       "type": "radio",
       "checked": "checked"}
    ),
    label({"for":"lastminute"}, "Lastminute"),

    input(
      {"id": "pauschal",
       "name": "choice",
       "type": "radio"}
    ),
    label({"for":"pauschal"}, "Pauschalreisen"),

    input(
      {"id": "hotels",
       "name": "choice",
       "type": "radio"}
    ),
    label({"for":"hotels"}, "Hotels"),

    input(
      {"id": "flights",
       "name": "choice",
       "type": "radio"}
    ),
    label({"for":"flights"}, "Flüge"),

    input(
      {"id": "fewo",
       "name": "choice",
       "type": "radio"}
    ),
    label({"for":"fewo"}, "Ferienhäuser")
  );
});
Jaml.register("infobox", function(div_id) {
  if(typeof(div_id) === 'object') {
    div_id = "infobox";
  }
  var div_pos_id = div_id + "_pos";
  var script_url = ["javascript","false;"].join(":");
  var ie_hack = '';
  if ($.browser.msie && parseInt($.browser.version, 10) < 7){
    ie_hack = iframe({src: script_url, frameborder: "0", scrolling: "no"});
  }
  div({id: div_pos_id},
    div({"id": div_id, "class": "infobox"},
      div({"class": "inner"},
        div({'class': 'content'}),
        div({"class": "icon1"},
          span({"class": "s_closepopup"})
        )
      )
    ),
    ie_hack
  );
});
Jaml.register("infobox_footer", function() {
  p({"class": "twenty"},
    span({"class": "s_phone"}),
    strong("0961 / 634 69 0"),
    "|",
    a({"href" : "mailto:Beratung@Nix-wie-weg.de", "class": "custom"},
      "E-Mail")
  );
});
Jaml.register("searchmask_lastminute", function() {
  form({"action": "", "autocomplete": "off"},
    div({"id": "pos"},
    div({"id": "searchengine"},
      input({id: "calendar", type: "hidden"}),
      div({"id": "row1"},
        ul(
          li(
            ul(
              Jaml.render("airport_part", 1),
              Jaml.render("destination_part", 2),
              Jaml.render("operator_part",
                {tabindex: 3, data: SearchMask.Operator.find_lastminute()}
              )
            )
          ),
          li(
            ul(
              Jaml.render("outgoing_part", {tabindex:4,
                                            caption: "Frühester Hinflug"}),
              Jaml.render("return_part",   {tabindex:5,
                                            caption: "Spätester Rückflug"}),
              Jaml.render("duration_part",
               {tabindex: 6, data: SearchMask.Duration.find_lastminute()}
              )
            ),
            li(
              ul(
                Jaml.render("traveler_part",
                  {tabindex: 7, data: SearchMask.Travelers.find_all()}),
                Jaml.render("children_part", 8),
                Jaml.render("search_open_part", 9)
              )
            )
          )
        ),
        div({"class":"clear"})
      ),
      div({"id": "row2", "style": "display: none;"},
        ul(
          li(
            Jaml.render("category_part", 10)
          ),
          li(
            ul({"id": "vorlieben"},
              li({"class": "bold"}, label("Vorlieben:") ),
                Jaml.render("affectation_part",
                  {"tabindex": 15, "label": "Speziell für Kinder",
                   "id": "family_children", "value": 0}),
                Jaml.render("affectation_part",
                  {"tabindex": 16, "label": "Direkte Strandlage",
                   "id": "beach", "value": 0}),
                Jaml.render("affectation_part",
                  {"tabindex": 17, "label": "Wellness-Fitness",
                   "id": "wellness", "value": 0}),
                Jaml.render("affectation_part",
                  {"tabindex": 18, "label": "Meerblick",
                   "id": "seaview", "value": 1048576}),
                Jaml.render("affectation_part",
                  {"tabindex": 19, "label": "Clubanlage",
                   "id": "club", "value": 0})
            )
          ),
          li(
            ul(
              Jaml.render("accomodation_type_part", {tabindex: 20}),
              Jaml.render("catering_part",
                {tabindex: 21, data: SearchMask.Catering.find_all()}),
              Jaml.render("sport_part",
                {tabindex: 22, data: SearchMask.Sport.find_all()})
            )
          )
        ),
        div({"class": "clear"})
      ),
      div({"id": "row3", "style": "display: none;"},
        ul(
          li(
            ul(
              li(
                textbox_with_label("hotel_name", "Hotelname:", 23, {})
              )
            )
          ),
          li(
            ul(
              Jaml.render("price_part")
            )
          ),
          li(
            ul(
              Jaml.render("search_close_part", 25)
            )
          )
        ),
        div({"class": "clear"})
      ),
      Jaml.render('infobox')
    )
    )
  );
});
Jaml.register("searchmask_simple_name_value_pair", function(object) {
  option({"value": object.get_value()}, h(object.name.toString()));
});
Jaml.register("searchmask_stars", function(category) {
  if(category.stars() === 0){
    span("egal");
  }else{
    for(var i=0; i < category.stars(); i++){
      span({"class": "s_star"});
    }
  }
});
Jaml.register("travelers_too_many_adults", function() {
  div(
    p(
      strong("Online sind max. 4 Erwachsene möglich.")
    ),
    p(
      a({"href" : "/mitarbeiter.html", "class": "custom"}, "Wir"),
      "helfen gerne persönlich für größere Gruppen:"),
    Jaml.render("infobox_footer")
  );
});
Jaml.register("accomodation_type_part", function(data) {
  var types = $.map(SearchMask.AccomodationType.find_all(), function(type) {
    return {value: type.form_value(), name: type.name};
  });
  li(
    select_with_label("accomodation_type_id", "Zimmertyp:", data.tabindex, {},
                      Jaml.render('option', types))
  );
});
Jaml.register("affectation_part", function(data) {
  li(
    checkbox_with_label(data.id, data.label, data.tabindex, {}, data.value)
  );
});
Jaml.register("airport_part", function(tabindex) {
  li({"class": "departure_airport"},
     textbox_with_label("departure_airport_status", "Abflughafen:",
                        tabindex, {readonly: "readonly"}),
     span({"class": "s_departure", "id": "airport_selector_img"}),
     Jaml.render('infobox', 'airportbox')
  );
});
Jaml.register('category_component_part', function(category) {
  li(
    input({id: 'category' + category.value, name: 'category_id',
           tabindex: category.tabindex, type: 'radio', value: category.value}),
    label({'for': 'category' + category.value},
      Jaml.render("searchmask_stars", category).replace(/\n/g,"")
    )
  );
});

Jaml.register("category_part", function(tabindex) {
  var categories = SearchMask.Category.find_all();
  $.each(categories, function(i, c) { c.tabindex = tabindex; });

  ul({"id": "category_id"},
    li(
      label("Hotelkategorie ",
            span({"class": "normal"}, "(ab):")
      )
    ),
    Jaml.render('category_component_part', categories)
  );
});
Jaml.register("catering_part", function(data) {
  li(
    label({"for": "catering_id"}, "Verpflegung ",
      span({"class": "normal"}, "(mind.):")
    ),
    select({"id": "catering_id", "name": "food", "tabindex": data.tabindex},
      Jaml.render("searchmask_simple_name_value_pair", data.data))
  );
});
Jaml.register("children_part", function(tabindex) {
  li({"class": "child", "id": "child_li"},
    input(
      {"id": "child",
       "name": "child",
       "tabindex": tabindex,
       "type": "checkbox"}),
    label({"class": "child", "for":"child"},
      "+",
      span({"class": "ages"},
      "Kinder"
      )
    ),
    span({"id": "children_number"}),
    Jaml.render('infobox', 'childrenbox')
  );
});
Jaml.register("destination_part", function(tabindex) {
  li({"class": "autocomplete"},
     label({"for":"destination_id"}, "Reiseziele:"),
     input({"id": "destination_id", "tabindex": tabindex,
           "name": "destination_id"}),
     div({"id": "dest_dropdown"})
   );
});
Jaml.register("duration_part", function(data) {
  li(
    select_with_label("duration_id", "Reisedauer:",
                      data.tabindex, {"class": "calendarwidth"},
                      Jaml.render("searchmask_simple_name_value_pair",
                                  data.data))
  );
});
Jaml.register("operator_part", function(data) {
  li(
    select_with_label("operator_id", "Reiseveranstalter:", data.tabindex, {},
      Jaml.render("searchmask_simple_name_value_pair", data.data)
    )
  );
});
Jaml.register("outgoing_part", function(data) {
  li({"class":"calendarwidth"},
     textbox_with_label("outgoing",
                        data.caption + ":",
                        data.tabindex,
                        {"class": "return.date-picker calendarwidth"}),
     span({"class": "butsh_calendar"})
   );
});
Jaml.register("price_part", function() {
  li(
    label({"for": "price"}, "Preis ",
      span({"class": "normal"}, "(pro Person):")
    ),
    input({"id": "price",
           "name": "preis",
           "maxlength": 4,
           "tabindex": "24",
           "type": "text"}
    ),
    strong("€")
  );
});
Jaml.register("return_part", function(data) {
  li({"class":"calendarwidth"},
    textbox_with_label("return",
                       data.caption + ":",
                       data.tabindex, {"class": "return.date-picker calendarwidth"}),
    span({"class": "butsh_calendar"})
  );
});
Jaml.register("search_close_part", function(tabindex) {
  li({"class":"search"},
    input({"class":"search",
           "tabindex": tabindex,
           "type": "button",
           "value": "Suche"}
    ),
    div({"id": "less"},
      span({"class": "s_close"}),
      span("Suche minimieren")
    )
  );
});
Jaml.register("search_open_part", function(tabindex) {
  li({"class":"search"},
    input(
      {"class":"search",
       "tabindex": tabindex,
       "type": "button",
       "value": "Suche"}
    ),
    div({"id": "more"},
      span({"class": "s_open"}),
      span(
        "Detailsuche"
      )
    )
  );
});
Jaml.register("sport_part", function(data) {
  li(
    select_with_label("sport_id", "Sportart:", data.tabindex, {},
      Jaml.render("searchmask_simple_name_value_pair", data.data)
    )
  );
});


Jaml.register("traveler_part", function(data) {
  li(
    select_with_label("traveler", "Reisende:", data.tabindex, {},
      Jaml.render("searchmask_simple_name_value_pair", data.data ))
  );
});

