function AutoSearch(container) {

  /* ---- Constants ---- */
  var actb_search_type_OR = 1;
  var actb_search_type_AND = 2;
  /* ---- Constants ---- */
  /* ---- Debug ---- */
  var actb_debug = false; // disables onblur, so we can inspect the elements
  /* ---- Debug ---- */


  /* ---- Public Variables ---- */
  this.actb_timeOut = -1; // Autocomplete Timeout in ms (-1: autocomplete never time out)
  this.actb_lim = -1;    // Number of elements autocomplete can show (-1: no limit)
  this.actb_firstText = false; // should the auto complete be limited to the beginning of keyword?
  this.actb_make_firstText = true; // should the auto complete be limited to the beginning of keyword?
  this.actb_mouse = true; // Enable Mouse Support
  this.actb_delimiter = new Array(" ");  // Delimiter for multiple autocomplete. Set it to empty array for single autocomplete
  this.actb_startcheck = 1; // Show widget only after this number of characters is typed in.
  this.actb_search_type = actb_search_type_AND; // Search type, (ex; AND, OR) - see _search_type_* constants
  this.actb_search_type_make = actb_search_type_OR; // Search type, (ex; AND, OR) - see _search_type_* constants
  this.actb_enable_report = true; //enable or disable reporting
  this.actb_report_min_length = 3; // do not report any results below this limit
  this.actb_result_threshold = 7;  //search results to display
  this.actb_make_result_threshold = 3;  //make search results to display

  this.actb_canvas_align = "right"; // "left" or "right". This are pseudo, not css values;
  this.actb_canvas_width = 301; // in px
  this.actb_canvas_top_margin = 5;
  this.reset_enabled = false;
  /* ---- Public Variables ---- */

  var instructions_text = 'Use up/down keys or mousewheel for more results.';

  /* --- Styles --- */
  this.actb_search_text_empty = 'actb_search_text_empty';
  this.actb_canvas_header = 'actb_canvas_header';
  this.actb_canvas_header_left = 'actb_canvas_header_left';
  this.actb_canvas_footer_left = 'actb_canvas_footer_left';
  this.actb_canvas_body = 'actb_canvas_body';
  this.actb_canvas_footer = 'actb_canvas_footer';
  this.actb_results_row = 'actb_results_row';
  this.actb_results_row_hi = 'actb_results_row_hi';
  /* --- Styles --- */

  this.actb_if_ie6 = false;
  /*@cc_on
    @if (@_jscript_version <= 5.6)
    // js code for IE6 or down
    this.actb_if_ie6 = true;
    @else @*/
  // js code for IE7 and non-IE browsers
  /*@end @*/


  /* --- URLS --- */
  function actb_write_model_redirect_url(make_name, model_name,
                                             search_text) {

      /* reporting */
      var report_text = actb_results_actions_prep_report();
      var report_arg = '';
      if (report_text.length) {
          report_arg = "&typo_search_text="+report_text;
      }
      /* reporting */

      // newcars.com/make/model/index.html
      return  "/"
              +toAlphaNumeric(make_name.toLowerCase())+"/"
              +toAlphaNumeric(model_name.toLowerCase())+"/"
              +"index.html"
              +"?searchresult=true"
              +"&searchresult_value="+search_text
              +report_arg
              +"&searchresult_uid="+actb_self.sUID
              +"&autosearch_ver="+actb_self.version
              +"";
  };
  function actb_write_make_redirect_url(make_name, search_text) {
      // newcars.com/make/index.html
      return  "/"
              +make_name.toLowerCase()+"/"
              +"index.html"
              +"?searchresult=true"
              +"&searchresult_value="+search_text
              +"&searchresult_uid="+actb_self.sUID
              +"&autosearch_ver="+actb_self.version
              +"";
  };

  function actb_write_report_url(search_text) {
       return  "/"
              +"?search_text="+search_text
              +"&searchresult_uid="+actb_self.sUID
              +"&autosearch_ver="+actb_self.version
              +"";
  };
  /* --- URLs --- */


  /* ---- Private Variables ---- */
  var actb_delimwords = new Array();
  var actb_cdelimword = 0;
  var actb_delimchar = new Array();
  var actb_display = false;
  var actb_pos = 0;
  var actb_top_pos = 0;
  var actb_total = 0;
  var actb_make_total = 0;
  var actb_curr = null;
  var actb_rangeu = 0;
  var actb_ranged = 0;
  var actb_bool = new Array();
  var actb_index = new Array();
  var actb_makes_bool = new Array();
  var actb_toid;
  var actb_mouse_on_list = 1;
  var actb_kwcount = 0;
  var actb_caretmove = false;
  var actb_last_value = '';
  var actb_prev_press_was_destroy_key = false;
  var actb_prev_press_was_destroy_key_text = '';
  var actb_new_query = '';
  var actb_reset_button = null;
  this.actb_keywords = new Array();
  this.actb_makes_keywords = new Array();
  this.sUID = guid();
  this.version = "0.1";
  /* ---- Private Variables---- */

  var actb_self = this;
  var actb_container = container;

  function actb_retrieveData() {
    var request = new Com.Ajax();
    request.ok = function(request){
        var data = Com.evalJSON(request.responseText);
        actb_keywords = data.AutoSearch.models_list;
        actb_makes_keywords = data.AutoSearch.makes_list;
        actb_start();
    };
    request.ex({url: '/cc/ajax/autosearch-data.php'});
  }

  function actb_start() {
      actb_removedisp();
      temp = actb_renderControls();
      actb_curr = temp.text_control;
      if (reset_enabled) { actb_reset_button = temp.reset_control; };
      actb_toggle_searchbox_decor();
      addEvent(actb_curr,"focus",actb_setup);
  }

  function actb_renderControls() {
      var t = document.createElement('input');
      t.setAttribute('type', 'text');
      t.setAttribute('id', 'actb_search_text');
      if (reset_enabled) {
          var r = document.createElement('img');
          r.setAttribute('id', 'actb_reset_button');
          r.setAttribute("src", 'http://images.newcars.com/images/actb/close.gif');
          r.setAttribute("style", "display: none;");
      };
      container.appendChild(t);
      if (reset_enabled) { container.appendChild(r); };
      return {text_control:t, reset_control:r};
  }

  function actb_setup(){
      if (reset_enabled) {
          addEvent(actb_reset_button,'click', actb_clear_searchbox);
      };
      addEvent(document,'keydown',actb_checkkey);
      if (!actb_debug) { addEvent(actb_curr,'blur', actb_clear); };
      addEvent(document,'keypress',actb_keypress);
      addEvent(document,'mousewheel',actb_wheel, false);
      var empty_search = actb_toggle_searchbox_decor();
      if (!empty_search) { actb_search_existing(); };
  };

  function actb_clear() {
      removeEvent(document,"keydown",actb_checkkey);
      if (!actb_debug) { removeEvent(actb_curr,"blur",actb_clear); };
      removeEvent(document,"keypress",actb_keypress);
      removeEvent(document,"mousewheel",actb_wheel, false);
      actb_removedisp();
      actb_toggle_searchbox_decor();
  };

  function actb_clear_searchbox() {
      actb_curr.value = '';
      actb_toggle_searchbox_decor();
  };

  // -- decorate seach box --- //
  /*
   * Return true if decorated, false if not
   */
  function actb_toggle_searchbox_decor(){
      if (actb_curr.value.length == 0) {
          actb_curr.className = actb_search_text_empty;
          actb_curr.value = 'Search';
          if (reset_enabled) { actb_reset_button.style.display='none'; };
          return true;
      };

      if (actb_curr.className == actb_search_text_empty) {
          actb_curr.value = '';
          actb_curr.className = '';
          if (reset_enabled) { actb_reset_button.style.display='block'; };
          return true;
      };

      return false;
  };

  function actb_search_existing() {
    setTimeout(function(){actb_tocomplete(0);},50);
  };



  //  -- format result search entry for display -- //
  function actb_parse(n){
      return n;
  };

  // -- resize iframe -- //
  function actb_iframe_resize() {
      if (this.actb_if_ie6) {
          var area = document.getElementById('actb_area_wrap');
          var area_iframe=document.getElementById('actb_select-free-iframe');
          area_iframe.style.height = area.offsetHeight + 'px';
      };
  };

  //  -- generate the drop down -- //
  function actb_generate(){

      var area = document.getElementById('actb_canvas_table');
      if (area) {
          //actb_display = false;

          // get header
          header_tr = area.rows[0];
          header_td = header_tr.cells[0];

          // get container
          container_tr = area.rows[2];
          container_td = container_tr.cells[0];

          // get footer
          footer_tr = area.rows[2];
          footer_td = footer_tr.cells[0];

          // get results table
          tb = document.getElementById('actb_results_table');
      }
      else {
          // create canvas
          var area_wrap = document.createElement('div');
          area_wrap.id = 'actb_area_wrap';

          if (this.actb_if_ie6) {
              var area_iframe = document.createElement('iframe');
              area_iframe.id = 'actb_select-free-iframe';
              area_iframe.frameBorder="0";
          };

          area_wrap.style.position='absolute';
          area_wrap.style.width=this.actb_canvas_width + "px";
          area_wrap.style.top = eval(curTop(actb_container) +
                                actb_container.offsetHeight) +
                            this.actb_canvas_top_margin + "px";
          area_wrap.style.left = curLeft(actb_container) + "px";

          area = document.createElement('table');
          area.id = 'actb_canvas_table';
          area.cellSpacing='0';
          area.cellPadding='0';
          area.style.width = area_wrap.style.width;

          // result table
          tb = document.createElement('table');
          tb.id = 'actb_results_table';
          tb.cellSpacing='0';
          tb.cellPadding='0';

          // create header
          header_tr = area.insertRow(-1);
          header_td = header_tr.insertCell(-1);
          header_td.className = actb_canvas_header;

          // create result container
          container_tr = area.insertRow(-1);
          container_td = container_tr.insertCell(-1);
          container_td.className = actb_canvas_body;
          container_td.appendChild(tb);

          // create footer
          footer_tr = area.insertRow(-1);
          footer_td = footer_tr.insertCell(-1);
          footer_td.className = actb_canvas_footer;

          /* iframe */
          if (this.actb_if_ie6) {
              area_iframe.style.width = area_wrap.style.width;
              area_wrap.appendChild(area_iframe);
          };

          area_wrap.appendChild(area);
          document.body.appendChild(area_wrap);

          if (actb_self.actb_mouse){
              addEvent(tb,"mouseout",actb_table_unfocus);
              addEvent(tb,"mouseover",actb_table_focus);
          };
      };

      var i;
      var j = 1;
      var counter = 0;
      if (actb_total == 0) {
          footer_tr.style.display="none";
          header_td.className = 'actb_canvas_header_tooltip';
          if (actb_curr.value.length < this.actb_startcheck) {
              header_td.innerHTML = "Please type in at least "
              + this.actb_startcheck
              + " letters";
          } else {
              header_td.innerHTML = '<img class="actb_warningIcon" src="http://images.newcars.com/images/actb/achtung.gif" width="43" height="40" alt="Warning icon" title="Warning icon" /><div class="actb_warningText">Sorry, we don\'t have a vehicle that matches what you searched for.  Try typing something like "Civic," "SUV," or even "hybrid truck."</div>';
          };
          actb_display = false;
      } else {
          footer_tr.style.display = "";
      };

      /* -- display found makes -- */
      var found_makes = new Array();
      for (i=0; i<actb_self.actb_makes_keywords.length; i++) {
          if (actb_makes_bool[i]) {
              var m = document.createElement("a");
              m.className='actb_make_link';
              var mu = actb_write_make_redirect_url(
                          actb_self.actb_makes_keywords[i],actb_curr.value);
              m.setAttribute("href", mu);
              addEvent(m,"mousedown",actb_make_mouseclick);
              m.style.cursor = 'pointer';
              m.innerHTML = actb_self.actb_makes_keywords[i];
              found_makes.push(m);
          };
      };

      footer_td.innerHTML = '';
      if (actb_index.length > actb_self.actb_result_threshold) {
          var instruction_div = document.createElement('div');
          instruction_div.className = 'actb_instructions';
          instruction_div.innerHTML = instructions_text;
          footer_td.appendChild(instruction_div);
      };

      if (found_makes.length) {
          var makes_div = document.createElement('div');
          makes_div.className = 'actb_makes';
          makes_div.appendChild(document.createTextNode("Possible Makes: "));
          for (i=0; i<found_makes.length;i++) {
              makes_div.appendChild(found_makes[i]);
              if (i < found_makes.length-1) {
                  makes_div.appendChild(document.createTextNode(", "));
              }
          };
          footer_td.appendChild(makes_div);
      }
      else {
          if (actb_total != 0) {
              if (footer_td.innerHTML.length == 0) {
                  footer_td.innerHTML = '&nbsp;';
              };
          }
      }
      /* -- display found makes -- */

      var first = true;
      var result_count = 0;
      var k;
      for (k=0; k<actb_index.length; k++) {
          i = actb_index[k];
          r = tb.rows[result_count];
          if (!r) { r = tb.insertRow(-1); };
          c = r.cells[0];
          if (!c) {
              c = r.insertCell(-1);
              c.id = 'actb_tr'+(j);
              c.uid = {image_url: null};
          };
          if (first) {
              c.className = actb_results_row_hi;
              first = false;
              actb_pos = counter;
              actb_top_pos = counter;
          }
          else { c.className = actb_results_row; };

          c = actb_thumbnail(c,i,j);
          result_count++;
          j++;
          if (result_count == actb_self.actb_result_threshold) {
              break;
          };
      };
      while (tb.rows.length-result_count) {
          tb.deleteRow(tb.rows.length-1);
      };
      actb_iframe_resize();

      actb_rangeu = 1;
      actb_ranged = j-1;
      if (actb_pos <= 0) { actb_pos = 1; };

      if (actb_total) {
          actb_display = true;
          header_td.className = actb_canvas_header;
          if (actb_total > result_count) {
              header_td.innerHTML = "We found " + actb_total +
                  " cars.";
          }
          else {
              header_td.innerHTML = "We found " + result_count + " cars";
          }
      };
  };

  function actb_thumbnail(c, idx, pos) {
      var url = "http://a137.g.akamai.net/f/137/3538/120m/"
                + "imageonthefly.cars.com/images/?IMG="
                + actb_self.actb_keywords[idx].image_string +
                ".jpg&WIDTH=67&HEIGHT=50&"+
                "NOIMG=NOIMAGE_CARSCOM_COMPARE.gif";

      var style = 'height: 50px; width: 67px; '+
              'min-height: 50px; min-width: 67px;';
      var image_style =
           "background-image: url('"+url+"'); "
          +"background-position: no-repeat; "
          +"border: 1px solid silver; "
          +"";

      /*
              '<img height="50" width="67" src="' + url + '">'+
      */

      if (c.uid == undefined || (c.uid && c.uid.image_url != url)) {
          c.innerHTML =
               '<div class="actb_results_div"><table border="0"><tr>'
              +'<td class="actb_results_image" style="'+style
              +'"valign="middle">'
              +'<div style="'+style+image_style+'"></div>'
              +'</td><td class="actb_results_text">'
              +actb_parse(actb_self.actb_keywords[idx].display)
              +'<br />'
              +actb_self.actb_keywords[idx].msrp_range
              +"</td></tr><table><div>";
          c.uid = {image_url:url};
      };
      c.id = 'actb_tr'+pos;
      c.setAttribute('pos',pos);
      if (actb_self.actb_mouse){
          c.style.cursor = 'pointer';
          addEvent(c,"mousedown",actb_mouseclick);
          addEvent(c,"mouseover",actb_table_highlight);
      };

      return c;
  };

  function actb_regenerate_down(nohighlight) {
      nohighlight = (nohighlight === undefined) ? false : nohighlight;
      actb_top_pos++;
      var i;
      var tb = document.getElementById('actb_results_table');
      // TODO: need remove handler here
      document.getElementById('actb_tr'+actb_pos).className = actb_results_row;
      tb.deleteRow(0);
      actb_iframe_resize();

      // re-number elements
      for (i=2; i<=actb_pos;i++) {
          document.getElementById('actb_tr'+i).id = 'actb_tr'+(i-1);
          document.getElementById('actb_tr'+(i-1)).setAttribute("pos",(i-1));
      };
      var r = tb.insertRow(-1);
      var c = r.insertCell(-1);
      c.className = (nohighlight === true) ? actb_results_row : actb_results_row_hi;

      i = actb_index[actb_pos+actb_top_pos-1];
      c = actb_thumbnail(c,i,actb_pos);
  };

  function actb_regenerate_up(nohighlight) {
      nohighlight = (nohighlight === undefined) ? false : nohighlight;
      actb_top_pos--;
      var i;
      var tb = document.getElementById('actb_results_table');
      // TODO: need remove handler here
      document.getElementById('actb_tr'+actb_pos).className = actb_results_row;
      tb.deleteRow(tb.rows.length-1);
      actb_iframe_resize();
      // re-number elements
      for (i=actb_result_threshold-1; i>=1; i--) {
          document.getElementById('actb_tr'+i).id = 'actb_tr'+(i+1);
          document.getElementById('actb_tr'+(i+1)).setAttribute("pos",(i+1));
      };

      var r = tb.insertRow(0);
      var c = r.insertCell(-1);
      c.className = (nohighlight === true) ? actb_results_row : actb_results_row_hi;

      i = actb_index[actb_top_pos];
      c = actb_thumbnail(c,i,actb_pos);
  };

  function actb_goup(nohighlight) {
      nohighlight = (nohighlight === undefined) ? false : nohighlight;
      if (!actb_display) { return; };
      var do_scroll = true;
      if (actb_total <= actb_self.actb_result_threshold) {
          do_scroll = false;
      };

      if (do_scroll && actb_pos == 1) {
          if ( (actb_top_pos+actb_pos) == 1) {
              return;
          } else {
              actb_regenerate_up(nohighlight);
              return;
          }
      };

      if (!do_scroll && actb_pos == 1) {
          return;
      };

      document.getElementById('actb_tr'+actb_pos).className = actb_results_row;
      actb_pos--;
      document.getElementById('actb_tr'+actb_pos).className = actb_results_row_hi;
  };

  function actb_scrolldown() {
    if (!actb_display) { return; };

    // all results are shown or we are on the last page - no scroll
    if (actb_total <= actb_self.actb_result_threshold ||
        (actb_total - actb_top_pos) <= actb_self.actb_result_threshold) {
      return;
    }
    var prev_pos = actb_pos;
    document.getElementById('actb_tr'+actb_pos).className = actb_results_row;
    actb_pos = actb_self.actb_result_threshold;
    actb_godown(true);
    actb_pos = prev_pos;
    document.getElementById('actb_tr'+actb_pos).className = actb_results_row_hi;
  }

  function actb_scrollup() {
    if (!actb_display) { return; };

    // all results are shown or we are on the first page  - no scroll
    if (actb_total <= actb_self.actb_result_threshold ||
        actb_top_pos === 0) {
      return;
    }
    var prev_pos = actb_pos;
    document.getElementById('actb_tr'+actb_pos).className = actb_results_row;
    actb_pos = 1;
    actb_goup(true);
    actb_pos = prev_pos;
    document.getElementById('actb_tr'+actb_pos).className = actb_results_row_hi;
  }

  function actb_godown(nohighlight) {
      nohighlight = (nohighlight === undefined) ? false : nohighlight;
      if (!actb_display) { return; };
      var do_scroll = true;
      var last_pos = 0;
      if (actb_total <= actb_self.actb_result_threshold) {
          do_scroll = false;
          last_pos = (actb_total < actb_self.actb_result_threshold) ?
                      actb_total : actb_self.actb_result_threshold;
      };

      if (do_scroll && actb_pos == actb_self.actb_result_threshold) {
          if ( (actb_top_pos+actb_pos) == actb_total) {
              return;
          } else {
              actb_regenerate_down(nohighlight);
              return;
          }
      };

      if (!do_scroll && actb_pos == last_pos) {
          return;
      };

      document.getElementById('actb_tr'+actb_pos).className = actb_results_row;
      actb_pos++;
      document.getElementById('actb_tr'+actb_pos).className = actb_results_row_hi;


      /* reporting */
      if (actb_new_query && (actb_pos == 1)) {
          actb_doreport(actb_results_actions_prep_report());
      };
      /* reporting */

  };

  function actb_movedown() {
      actb_rangeu++;
      actb_ranged++;
  }
  function actb_moveup() {
      actb_rangeu--;
      actb_ranged--;
  }

  /* Mouse */
  function actb_make_mouseclick(evt){
      if (!evt) { evt = event; };
      if (!actb_display) { return; };
      actb_mouse_on_list = 0;
      window.location.href = this.getAttribute('href');
  };

  function actb_mouseclick(evt){
      if (!evt) { evt = event; };
      if (!actb_display) { return; };
      actb_mouse_on_list = 0;
      actb_pos = this.getAttribute('pos');
      actb_penter();
  }

  /** Event handler for mouse wheel event.
   */
  function actb_wheel(evt){
      if (!evt) { evt = event; };
      var delta = 0;
      delta = getWheelDelta(evt);
      if (delta) { actb_handle_wheel(delta); };
      stopEvent(evt);
  };

  function actb_handle_wheel(delta) {
      if (delta < 0) {
          actb_scrolldown();
      } else {
          actb_scrollup();
      };
  };

  function actb_table_focus() {
      actb_mouse_on_list = 1;
  }
  function actb_table_unfocus() {
      actb_mouse_on_list = 0;
      if (actb_toid) clearTimeout(actb_toid);
      if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list = 0;actb_removedisp();},actb_self.actb_timeOut);
  }
  function actb_table_highlight(){
      actb_mouse_on_list = 1;
      document.getElementById('actb_tr'+actb_pos).className = actb_results_row;
      actb_pos = parseInt(this.getAttribute('pos'));
      while (actb_pos < actb_rangeu) { actb_moveup(); };
      while (actb_pos > actb_ranged) { actb_movedown(); };
      document.getElementById('actb_tr'+actb_pos).className = actb_results_row_hi;
      if (actb_toid) { clearTimeout(actb_toid); };
      if (actb_self.actb_timeOut > 0) {
          actb_toid = setTimeout(
                       function(){actb_mouse_on_list = 0;actb_removedisp();},
                       actb_self.actb_timeOut);
      };
  }
  /* ---- */

  function actb_penter(){
      if (!actb_display) { return; };
      actb_display = false;
      var word = '';
      var c = 0;
      var curr_result = null;
      var wtf = parseInt(actb_pos)+parseInt(actb_top_pos); // WTF parseInt()????
      for (var i=0;i<=actb_self.actb_keywords.length;i++) {
          if (actb_bool[i]) { c++; };
          if (c === wtf) { //(actb_pos+actb_top_pos)) {
              word = actb_self.actb_keywords[i].search;
              curr_result = actb_self.actb_keywords[i];
              break;
          };
      };
      if (curr_result) {
          actb_removedisp();
          window.location.href =
              actb_write_model_redirect_url(curr_result.make_name,
                                            curr_result.model_name,
                                            actb_curr.value);
      };
  };

  function actb_doreport(report_text) {
      if (!actb_self.actb_enable_report) { return; };
      if (report_text.length >= actb_report_min_length) {
          simpleXHR(actb_write_report_url(report_text));
      }
  }


  function actb_removedisp() {
      actb_display = 0;
      if (document.getElementById('actb_area_wrap')) {
          document.body.removeChild(document.getElementById('actb_area_wrap'));
      }
      if (actb_toid) { clearTimeout(actb_toid); };
  };

  function actb_keypress(e){
      if (actb_caretmove) stopEvent(e);
      return !actb_caretmove;
  }
  function actb_checkkey(evt){
      if (!evt) evt = event;
      a = evt.keyCode;
      caret_pos_start = getCaretStart(actb_curr);
      actb_caretmove = 0;
      switch (a){
          case 38:
              actb_goup();
              actb_caretmove = 1;
              return false;
              break;
          case 40:
              actb_godown();
              actb_caretmove = 1;
              return false;
              break;
          case 13: case 9:
              if (actb_display){
                  actb_caretmove = 1;
                  actb_penter();
                  return false;
              }else{
                  return true;
              }
              break;
          default:
              setTimeout(function(){actb_tocomplete(a);},50);
              break;
      };
  };

  function actb_results_actions_prep_report() {
      actb_new_query = false;
      actb_prev_press_was_destroy_key = false;
      var report_text = actb_prev_press_was_destroy_key_text;
      actb_prev_press_was_destroy_key_text = '';
      if (report_text.length==0) { report_text = actb_last_value; };
      return report_text;
  };


 function actb_prep_report(kc){
      var report_text = '';
      actb_new_query = false;
      var multiple_letter_change = false;
      var new_text_after_destroy = false;

      if (actb_last_value != actb_curr.value) {
          actb_new_query = true;
          /* see if we have a change thats more then one letter */
          if (Math.abs(actb_last_value.length - actb_curr.value.length)>1) {
              multiple_letter_change = true;
              report_text = actb_last_value;
          }
      };

      /* when one of the destroy keys is continuously hit */
      var just_pressed_destroy = false;
      if (kc == 8 || kc == 46) {
          just_pressed_destroy = true;
          if (!actb_prev_press_was_destroy_key) {
              actb_prev_press_was_destroy_key_text = actb_last_value;
          }
          actb_prev_press_was_destroy_key = true;
      };

      if (actb_new_query) {
          /* when one of the destroy keys is repeatedly hit (cont. above) */
          if (actb_prev_press_was_destroy_key && !just_pressed_destroy) {
              actb_prev_press_was_destroy_key = false;
              report_text = actb_prev_press_was_destroy_key_text;
              actb_prev_press_was_destroy_key_text = '';
              new_text_after_destroy = true;
          };
      }

      if (actb_new_query) {
          actb_last_value = actb_curr.value;
      };

      if (report_text &&
          actb_new_query &&
          ((multiple_letter_change && just_pressed_destroy) ||
           new_text_after_destroy)) {
          return report_text;
      };

      return '';

  };

  function actb_tocomplete(kc){

      if (kc == 38 || kc == 40 || kc == 13) {return;};

      actb_doreport(actb_prep_report(kc));

      var i;
      if (actb_display){
          var word = 0;
          var c = 0;
          for (i=0;i<=actb_self.actb_keywords.length;i++){
              if (actb_bool[i]) c++;
              if (c == actb_pos){
                  word = i;
                  break;
              }
          }
      }

      if (actb_curr.value == ''){
          actb_mouse_on_list = 0;
          actb_removedisp();
          return;
      }


      var t_arr = new Array();
      if (actb_self.actb_delimiter.length > 0){
          caret_pos_start = getCaretStart(actb_curr);
          caret_pos_end = getCaretEnd(actb_curr);

          delim_split = '';
          for (i=0;i<actb_self.actb_delimiter.length;i++){
              delim_split += actb_self.actb_delimiter[i];
          }
          delim_split = addslashes(delim_split);
          delim_split_rx = new RegExp("(["+delim_split+"])");
          c = 0;
          actb_delimwords = new Array();
          actb_delimwords[0] = '';
          for (i=0,j=actb_curr.value.length;i<actb_curr.value.length;i++,j--){
              if (actb_curr.value.substr(i,j).search(delim_split_rx) == 0){
                  ma = actb_curr.value.substr(i,j).match(delim_split_rx);
                  actb_delimchar[c] = ma[1];
                  c++;
                  actb_delimwords[c] = '';
              }else{
                  actb_delimwords[c] += actb_curr.value.charAt(i);
              }
          }

          var l = 0;
          actb_cdelimword = -1;
          for (i=0;i<actb_delimwords.length;i++){
              if (caret_pos_end >= l && caret_pos_end <= l + actb_delimwords[i].length){
                  actb_cdelimword = i;
              }
              l+=actb_delimwords[i].length + 1;
          }
          for (i=0; i<actb_delimwords.length;i++) {
              if (trim(actb_delimwords[i]).length > 0) {
                  t_arr.push({word: actb_delimwords[i],
                              search: trim(addslashes(actb_delimwords[i]))});
              }
          };
      }

      actb_total = 0;
      actb_kwcount = 0;
      actb_index = [];
      for (i=0;i<actb_self.actb_keywords.length;i++) {
          actb_bool[i] = false;
          var matches_found = actb_filter(actb_self.actb_keywords[i].search,
                                          t_arr,
                                          actb_self.actb_startcheck,
                                          actb_self.actb_search_type,
                                          actb_self.actb_firstText
                                          );
         if (matches_found) {
              actb_total++;
              actb_bool[i] = true;
              actb_index.push(i);
              actb_kwcount++;
         };
      };

      actb_make_total = 0;
      done = false;
      for (i=0;i<actb_self.actb_makes_keywords.length;i++) {
          actb_makes_bool[i] = false;
          if (!done) {
              var matches_found =
                  actb_filter(actb_self.actb_makes_keywords[i],
                              t_arr,
                              actb_self.actb_startcheck,
                              actb_self.actb_search_type_make,
                              actb_self.actb_make_firstText
                              );

              if (matches_found) {
                  actb_make_total++;
                  actb_makes_bool[i] = true;
                  if ( actb_make_total ==
                       actb_self.actb_make_result_threshold) {
                      done = true;
                  };
              };
          };
      };
      if (actb_toid) { clearTimeout(actb_toid); };
      if (actb_self.actb_timeOut > 0) {
          actb_toid = setTimeout(function(){actb_mouse_on_list = 0;
                                            actb_removedisp();},
                                 actb_self.actb_timeOut);
      };
      actb_generate();
  };


  function actb_filter(search_string, search_words, min_word_len,
                       search_type, from_start) {

      /* this should be refactored */
      var match_found = false;
      var skipped = 0;
      if (search_type==actb_search_type_AND && search_words.length) {
          match_found = true;
      };
      for (j=0; j<search_words.length;j++) {
          // if word is not long enough, skip it
          if (search_words[j].word.length < min_word_len) {
              skipped++;
              continue;
          };
          if (from_start) {
              var re = new RegExp("^" + search_words[j].search, "i");
          } else {
              var re = new RegExp(search_words[j].search, "i");
          }
          if (search_type == actb_search_type_AND) {
              if (!re.test(search_string)) {
                  match_found = false;
              };
          }
          else if (search_type == actb_search_type_OR) {
              if (re.test(search_string)) {
                  match_found = true;
                  break;
              };
          };
      };
      if (skipped == search_words.length) {  match_found = false; };
      return match_found;
  };


  /* guid */
  function S4() {
     return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
  }
  function guid() {
     return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
  }

  /* XHR */
  function simpleXHR(url) {
    var request = new Com.Ajax();
    request.ex({url : url});
  }

  /* Event Functions */

  // Add an event to the obj given
  // event_name refers to the event trigger, without the "on", like click or mouseover
  // func_name refers to the function callback when event is triggered
  function addEvent(obj,event_name,func_name, bubble){
      if (bubble == undefined) { bubble = true; };
      if (obj.attachEvent){
          //obj.attachEvent("on"+event_name, func_name);
          // stupid IE mouseover handling issues.
          // lets use Dom0
          //obj.attachEvent("on"+event_name, func_name);
          obj["on"+event_name] = func_name;
      } else if(obj.addEventListener){
          if (event_name == 'mousewheel') { event_name = 'DOMMouseScroll'; };
          obj.addEventListener(event_name,func_name, bubble);
      } else {
          obj["on"+event_name] = func_name;
      }
  }

  // Removes an event from the object
  function removeEvent(obj,event_name,func_name,bubble){
      if (bubble == undefined) { bubble = true; };
      if (obj.detachEvent){
          //obj.attachEvent("on"+event_name, func_name);
          // stupid IE mouseover handling issues.
          // lets use Dom0
          //obj.detachEvent("on"+event_name,func_name);
          obj["on"+event_name] = null;
      }else if(obj.removeEventListener){
          if (event_name == 'mousewheel') { event_name = 'DOMMouseScroll'; };
          obj.removeEventListener(event_name,func_name,bubble);
      }else{
          obj["on"+event_name] = null;
      }
  }

  // Stop an event from bubbling up the event DOM
  function stopEvent(evt){
      evt = evt || window.event;
      if (evt.stopPropagation){
          evt.stopPropagation();
          evt.preventDefault();
      }else if(typeof evt.cancelBubble != "undefined"){
          evt.cancelBubble = true;
          evt.returnValue = false;
      }
      return false;
  }

  // Get the obj that starts the event
  function getElement(evt){
      if (window.event){
          return window.event.srcElement;
      }else{
          return evt.currentTarget;
      }
  }
  // Get the obj that triggers off the event
  function getTargetElement(evt){
      if (window.event){
          return window.event.srcElement;
      }else{
          return evt.target;
      }
  }
  // For IE only, stops the obj from being selected
  function stopSelect(obj){
      if (typeof obj.onselectstart != 'undefined'){
          addEvent(obj,"selectstart",function(){ return false;});
      }
  }

  // Retrieve wheel delta, negative if down, positive if up, 0 for no move.
  function getWheelDelta(evt) {
      if (evt.wheelDelta) {
          /* IE/Opera. */
          delta = evt.wheelDelta/120;
          /** In Opera 9, delta differs in sign as compared to IE.
           */
          if (window.opera) { delta = -delta; };
      } else if (evt.detail) {
          /** Mozilla case. */
          /** In Mozilla, sign of delta is different than in IE.
           * Also, delta is multiple of 3.
           */
          delta = -evt.detail/3;
      };
      return delta;
  };

  /*    Caret Functions     */

  // Get the end position of the caret in the object. Note that the obj needs to be in focus first
  function getCaretEnd(obj){
      if(typeof obj.selectionEnd != "undefined"){
          return obj.selectionEnd;
      }else if(document.selection&&document.selection.createRange){
          var M=document.selection.createRange();
          try{
              var Lp = M.duplicate();
              Lp.moveToElementText(obj);
          }catch(e){
              var Lp=obj.createTextRange();
          }
          Lp.setEndPoint("EndToEnd",M);
          var rb=Lp.text.length;
          if(rb>obj.value.length){
              return -1;
          }
          return rb;
      }
  }
  // Get the start position of the caret in the object
  function getCaretStart(obj){
      if(typeof obj.selectionStart != "undefined"){
          return obj.selectionStart;
      }else if(document.selection&&document.selection.createRange){
          var M=document.selection.createRange();
          try{
              var Lp = M.duplicate();
              Lp.moveToElementText(obj);
          }catch(e){
              var Lp=obj.createTextRange();
          }
          Lp.setEndPoint("EndToStart",M);
          var rb=Lp.text.length;
          if(rb>obj.value.length){
              return -1;
          }
          return rb;
      }
  }
  // sets the caret position to l in the object
  function setCaret(obj,l){
      obj.focus();
      if (obj.setSelectionRange){
          obj.setSelectionRange(l,l);
      }else if(obj.createTextRange){
          m = obj.createTextRange();
          m.moveStart('character',l);
          m.collapse();
          m.select();
      }
  }
  // sets the caret selection from s to e in the object
  function setSelection(obj,s,e){
      obj.focus();
      if (obj.setSelectionRange){
          obj.setSelectionRange(s,e);
      }else if(obj.createTextRange){
          m = obj.createTextRange();
          m.moveStart('character',s);
          m.moveEnd('character',e);
          m.select();
      }
  }

  /*    Escape function   */
  function toAlphaNumeric(s){
      return s.replace(/[^a-zA-Z0-9]+/g,'');
  };


  /* --- Escape --- */

  /* Offset position from top of the screen */
  function curTop(obj){
      toreturn = 0;
      while(obj){
          toreturn += obj.offsetTop;
          obj = obj.offsetParent;
      }
      return toreturn;
  }
  function curLeft(obj){
      toreturn = 0;
      while(obj){
        if (obj.id !== "actb_search_box"){
          toreturn += obj.offsetLeft;
        }
        obj = obj.offsetParent;
      }
      return toreturn;
  }
  function curRight(obj){
      toreturn = 0;
      while(obj){
          toreturn += obj.offsetLeft;
          obj = obj.offsetParent;
      }
      return toreturn;
  }

  /* ------ End of Offset function ------- */

  /* Types Function */

  // is a given input a number?
  function isNumber(a) {
      return typeof a == 'number' && isFinite(a);
  }

  /* Object Functions */

  function replaceHTML(obj,text){
      while ( el == obj.childNodes[0] ){
          obj.removeChild(el);
      };
      obj.appendChild(document.createTextNode(text));
  }

  function trim(s) {
      return s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
  };

  function addslashes(s){
      return s.replace(/(["\\\.\|\[\]\^\*\+\?\$\(\)])/g, '\\$1');
  };


  actb_retrieveData();
  return this;
}
