/**
* jquery-autocompleter v0.4.0-0 - 2020-01-04
* Easy customisable and with localStorage cache support.
* http://github.com/fitiskin/jquery-autocompleter
*
* @license (c) 2020 Artem Fitiskin MIT Licensed
*/

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) :
  typeof define === 'function' && define.amd ? define(['jquery'], factory) :
  (global = global || self, factory(global.$));
}(this, (function ($) { 'use strict';

  $ = $ && $.hasOwnProperty('default') ? $['default'] : $;

  function _typeof(obj) {
    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
      _typeof = function (obj) {
        return typeof obj;
      };
    } else {
      _typeof = function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
      };
    }

    return _typeof(obj);
  }

  var guid = 0,
      ignoredKeyCode = [9, 13, 17, 19, 20, 27, 33, 34, 35, 36, 37, 39, 44, 92, 113, 114, 115, 118, 119, 120, 122, 123, 144, 145],
      allowOptions = ["source", "empty", "limit", "cache", "cacheExpires", "focusOpen", "selectFirst", "changeWhenSelect", "highlightMatches", "ignoredKeyCode", "customLabel", "customValue", "template", "offset", "combine", "callback", "minLength", "delay"],
      userAgent = window.navigator.userAgent || window.navigator.vendor || window.opera,
      isFirefox = /Firefox/i.test(userAgent),
      isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(userAgent),
      isFirefoxMobile = isFirefox && isMobile,
      $body = null,
      delayTimeout = null,
      localStorageKey = "autocompleterCache",
      supportLocalStorage = function () {
    var supported = typeof window.localStorage !== "undefined";

    if (supported) {
      try {
        localStorage.setItem("autocompleter", "autocompleter");
        localStorage.removeItem("autocompleter");
      } catch (e) {
        supported = false;
      }
    }

    return supported;
  }();
  /**
   * Don't forget update README.md
   *
   * @options
   * @param source [(string|object)] <null> "URL to the server or a local object"
   * @param asLocal [boolean] <false> "Parse remote response as local source"
   * @param empty [boolean] <true> "Launch if value is empty"
   * @param limit [int] <10> "Number of results to be displayed"
   * @param minLength [int] <0> "Minimum length for autocompleter"
   * @param delay [int] <0> "Few milliseconds to defer the request"
   * @param customClass [array] <[]> "Array with custom classes for autocompleter element"
   * @param cache [boolean] <true> "Save xhr data to localStorage to avoid the repetition of requests"
   * @param cacheExpires [int] <86400> "localStorage data lifetime"
   * @param focusOpen [boolean] <true> "Launch autocompleter when input gets focus"
   * @param hint [boolean] <false> "Add hint to input with first matched label, correct styles should be installed"
   * @param selectFirst [boolean] <false> "If set to true, first element in autocomplete list will be selected automatically, ignore if changeWhenSelect is on"
   * @param changeWhenSelect [boolean] <true> "Allows to change input value using arrow keys navigation in autocomplete list"
   * @param highlightMatches [boolean] <false> "This option defines <strong> tag wrap for matches in autocomplete results"
   * @param ignoredKeyCode [array] <[]> "Array with ignorable keycodes"
   * @param customLabel [boolean] <false> "The name of object's property which will be used as a label"
   * @param customValue [boolean] <false> "The name of object's property which will be used as a value"
   * @param template [(string|boolean)] <false> "Custom template for list items"
   * @param offset [(string|boolean)] <false> "Source response offset, for example: response.items.posts"
   * @param combine [function] <null> "Returns an object with ajax data. Useful if you want to pass some additional server options or replace it at all"
   * @param callback [function] <$.noop> "Select value callback function. Arguments: value, index"
   */


  var options = {
    source: null,
    asLocal: false,
    empty: true,
    limit: 10,
    minLength: 0,
    delay: 0,
    customClass: [],
    cache: true,
    cacheExpires: 86400,
    focusOpen: true,
    hint: false,
    selectFirst: false,
    changeWhenSelect: true,
    highlightMatches: false,
    ignoredKeyCode: [],
    customLabel: false,
    customValue: false,
    template: false,
    offset: false,
    combine: null,
    callback: $.noop
  };
  var publics = {
    /**
     * @method
     * @name defaults
     * @description Sets default plugin options
     * @param opts [object] <{}> "Options object"
     * @example $.autocompleter('defaults', opts);
     */
    defaults: function defaults(opts) {
      options = $.extend(options, opts || {});
      return _typeof(this) === "object" ? $(this) : true;
    },

    /**
     * @method
     * @name option
     * @description Open autocompleter list
     */
    option: function option(properties) {
      return $(this).each(function (i, input) {
        var data = $(input).next(".autocompleter").data("autocompleter");

        for (var property in properties) {
          if ($.inArray(property, allowOptions) !== -1) {
            data[property] = properties[property];
          }
        }
      });
    },

    /**
     * @method
     * @name open
     * @description Open autocompleter list
     */
    open: function open() {
      return $(this).each(function (i, input) {
        var data = $(input).next(".autocompleter").data("autocompleter");

        if (data) {
          _open(null, data);
        }
      });
    },

    /**
     * @method
     * @name close
     * @description Close autocompleter list
     */
    close: function close() {
      return $(this).each(function (i, input) {
        var data = $(input).next(".autocompleter").data("autocompleter");

        if (data) {
          _close(null, data);
        }
      });
    },

    /**
     * @method
     * @name clearCache
     * @description Remove localStorage cache
     */
    clearCache: function clearCache() {
      _deleteCache();
    },

    /**
     * @method
     * @name destroy
     * @description Removes instance of plugin
     * @example $('.target').autocompleter('destroy');
     */
    destroy: function destroy() {
      return $(this).each(function (i, input) {
        var data = $(input).next(".autocompleter").data("autocompleter");

        if (data) {
          // Abort xhr
          if (data.jqxhr) {
            data.jqxhr.abort();
          } // If has selected item & open - confirm it


          if (data.$autocompleter.hasClass("open")) {
            data.$autocompleter.find(".autocompleter-selected").trigger("click.autocompleter");
          } // Restore original autocomplete attr


          if (!data.originalAutocomplete) {
            data.$node.removeAttr("autocomplete");
          } else {
            data.$node.attr("autocomplete", data.originalAutocomplete);
          } // Remove autocompleter & unbind events


          data.$node.off(".autocompleter").removeClass("autocompleter-node");
          data.$autocompleter.off(".autocompleter").remove();
        }
      });
    }
  };
  /**
   * @method private
   * @name _init
   * @description Initializes plugin
   * @param opts [object] "Initialization options"
   */

  function _init(opts) {
    // Local options
    opts = $.extend({}, options, opts || {}); // Check for Body

    if ($body === null) {
      $body = $("body");
    } // Apply to each element


    var $items = $(this);

    for (var i = 0, count = $items.length; i < count; i++) {
      _build($items.eq(i), opts);
    }

    return $items;
  }
  /**
   * @method private
   * @name _build
   * @description Builds each instance
   * @param $node [jQuery object] "Target jQuery object"
   * @param opts [object] <{}> "Options object"
   */


  function _build($node, opts) {
    if (!$node.hasClass("autocompleter-node")) {
      // Extend options
      opts = $.extend({}, opts, $node.data("autocompleter-options")); // Check for as local or .json file

      if (typeof opts.source === "string" && (opts.source.slice(-5) === ".json" || opts.asLocal === true)) {
        $.ajax({
          url: opts.source,
          type: "GET",
          dataType: "json",
          async: false
        }).done(function (response) {
          opts.source = response;
        });
      }

      var html = '<div class="autocompleter ' + opts.customClass.join(" ") + '" id="autocompleter-' + (guid + 1) + '">';

      if (opts.hint) {
        html += '<div class="autocompleter-hint"></div>';
      }

      html += '<ul class="autocompleter-list"></ul>';
      html += "</div>";
      $node.addClass("autocompleter-node").after(html);
      var $autocompleter = $node.next(".autocompleter").eq(0); // Set autocomplete to off for warn overlay

      var originalAutocomplete = $node.attr("autocomplete");
      $node.attr("autocomplete", "off"); // Store plugin data

      var data = $.extend({
        $node: $node,
        $autocompleter: $autocompleter,
        $selected: null,
        $list: null,
        index: -1,
        hintText: false,
        source: false,
        jqxhr: false,
        response: null,
        focused: false,
        query: "",
        originalAutocomplete: originalAutocomplete,
        guid: guid++
      }, opts); // Bind autocompleter events

      data.$autocompleter.on("mousedown.autocompleter", ".autocompleter-item", data, _select).data("autocompleter", data); // Bind node events

      data.$node.on("keyup.autocompleter", data, _onKeyup).on("keydown.autocompleter", data, _onKeydown).on("focus.autocompleter", data, _onFocus).on("blur.autocompleter", data, _onBlur).on("mousedown.autocompleter", data, _onMousedown);
    }
  }
  /**
   * @method private
   * @name _search
   * @description Local search function, return best collation
   * @param query [string] "Query string"
   * @param source [object] "Source data"
   * @param data [object] "Instance data"
   */


  function _search(query, source, data) {
    var response = [];
    query = query.toUpperCase();

    if (source.length) {
      for (var i = 0; i < 2; i++) {
        for (var item in source) {
          if (response.length < data.limit) {
            var label = data.customLabel && source[item][data.customLabel] ? source[item][data.customLabel] : source[item].label;

            switch (i) {
              case 0:
                if (label.toUpperCase().search(query) === 0) {
                  response.push(source[item]);
                  delete source[item];
                }

                break;

              case 1:
                if (label.toUpperCase().search(query) !== -1) {
                  response.push(source[item]);
                  delete source[item];
                }

                break;
            }
          }
        }
      }
    }

    return response;
  }
  /**
   * @method private
   * @name _launch
   * @description Launch autocompleter
   * @param data [object] "Instance data"
   */


  function _launch(data) {
    // Clear previous timeout
    clearTimeout(delayTimeout);
    data.query = $.trim(data.$node.val());

    if (!data.empty && data.query.length === 0 || data.minLength && data.query.length < data.minLength) {
      _clear(data);

      return;
    }

    if (data.delay) {
      // Be careful: delay used also with local source
      delayTimeout = setTimeout(function () {
        _xhr(data);
      }, data.delay);
    } else {
      _xhr(data);
    }
  }
  /**
   * @method private
   * @name _xhr
   * @description Use source locally or create xhr
   * @param data [object] "Instance data"
   */


  function _xhr(data) {
    if (_typeof(data.source) === "object") {
      _clear(data); // Local search


      var search = _search(data.query, _clone(data.source), data);

      if (search.length) {
        _response(search, data);
      }
    } else {
      if (data.jqxhr) {
        data.jqxhr.abort();
      }

      var ajaxData = {
        limit: data.limit,
        query: data.query
      };

      if (typeof data.combine === "function") {
        ajaxData = data.combine(ajaxData);
      }

      data.jqxhr = $.ajax({
        url: data.source,
        dataType: "json",
        crossDomain: true,
        data: ajaxData,
        beforeSend: function beforeSend(xhr) {
          data.$autocompleter.addClass("autocompleter-ajax");

          _clear(data);

          if (data.cache) {
            var stored = _getCache(this.url, data.cacheExpires);

            if (stored) {
              xhr.abort();

              _response(stored, data);
            }
          }
        }
      }).done(function (response) {
        // Get subobject from responce
        if (data.offset) {
          response = _grab(response, data.offset);
        } // Set cache


        if (data.cache) {
          _setCache(this.url, response);
        }

        _response(response, data);
      }).always(function () {
        data.$autocompleter.removeClass("autocompleter-ajax");
      });
    }
  }
  /**
   * @method private
   * @name _clear
   * @param data [object] "Instance data"
   */


  function _clear(data) {
    // Clear data
    data.response = null;
    data.$list = null;
    data.$selected = null;
    data.index = 0;
    data.$autocompleter.find(".autocompleter-list").empty();
    data.$autocompleter.find(".autocompleter-hint").removeClass("autocompleter-hint-show").empty();
    data.hintText = false;

    _close(null, data);
  }
  /**
   * @method private
   * @name _response
   * @description Main source response function
   * @param response [object] "Source data"
   * @param data [object] "Instance data"
   */


  function _response(response, data) {
    _buildList(response, data);

    if (data.$autocompleter.hasClass("autocompleter-focus")) {
      _open(null, data);
    }
  }
  /**
   * @method private
   * @name _buildList
   * @description Generate autocompleter-list and update instance data by source
   * @param list [object] "Source data"
   * @param data [object] "Instance data"
   */


  function _buildList(list, data) {
    var menu = "";

    for (var item = 0, count = list.length; item < count; item++) {
      var classes = ["autocompleter-item"],
          highlightReg = new RegExp(data.query, "gi");

      if (data.selectFirst && item === 0 && !data.changeWhenSelect) {
        classes.push("autocompleter-item-selected");
      }

      var label = data.customLabel && list[item][data.customLabel] ? list[item][data.customLabel] : list[item].label,
          clear = label;
      label = data.highlightMatches ? label.replace(highlightReg, "<strong>$&</strong>") : label;
      var value = data.customValue && list[item][data.customValue] ? list[item][data.customValue] : list[item].value; // Apply custom template

      if (data.template) {
        var template = data.template.replace(/({{ label }})/gi, label);

        for (var property in list[item]) {
          if (Object.prototype.hasOwnProperty.call(list[item], property)) {
            var regex = new RegExp("{{ " + property + " }}", "gi");
            template = template.replace(regex, list[item][property]);
          }
        }

        label = template;
      }

      if (value) {
        menu += '<li data-value="' + value + '" data-label="' + clear + '" class="' + classes.join(" ") + '">' + label + "</li>";
      } else {
        menu += '<li data-label="' + clear + '" class="' + classes.join(" ") + '">' + label + "</li>";
      }
    } // Set hint


    if (list.length && data.hint) {
      var hintLabel = data.customLabel && list[0][data.customLabel] ? list[0][data.customLabel] : list[0].label,
          hint = hintLabel.substr(0, data.query.length).toUpperCase() === data.query.toUpperCase() ? hintLabel : false;

      if (hint && data.query !== hintLabel) {
        var hintReg = new RegExp(data.query, "i");
        var hintText = hint.replace(hintReg, "<span>" + data.query + "</span>");
        data.$autocompleter.find(".autocompleter-hint").addClass("autocompleter-hint-show").html(hintText);
        data.hintText = hintText;
      }
    } // Update data


    data.response = list;
    data.$autocompleter.find(".autocompleter-list").html(menu);
    data.$selected = data.$autocompleter.find(".autocompleter-item-selected").length ? data.$autocompleter.find(".autocompleter-item-selected") : null;
    data.$list = list.length ? data.$autocompleter.find(".autocompleter-item") : null;
    data.index = data.$selected ? data.$list.index(data.$selected) : -1;
    data.$autocompleter.find(".autocompleter-item").each(function (i, j) {
      $(j).data(data.response[i]);
    });
  }
  /**
   * @method private
   * @name _onKeyup
   * @description Keyup events in node, up/down autocompleter-list navigation, typing and enter button callbacks
   * @param e [object] "Event data"
   */


  function _onKeyup(e) {
    var data = e.data,
        code = e.keyCode ? e.keyCode : e.which;

    if ((code === 40 || code === 38) && data.$autocompleter.hasClass("autocompleter-show")) {
      // Arrows up & down
      var len = data.$list.length,
          next,
          prev;

      if (len) {
        // Determine new index
        if (len > 1) {
          if (data.index === len - 1) {
            next = data.changeWhenSelect ? -1 : 0;
            prev = data.index - 1;
          } else if (data.index === 0) {
            next = data.index + 1;
            prev = data.changeWhenSelect ? -1 : len - 1;
          } else if (data.index === -1) {
            next = 0;
            prev = len - 1;
          } else {
            next = data.index + 1;
            prev = data.index - 1;
          }
        } else if (data.index === -1) {
          next = 0;
          prev = 0;
        } else {
          prev = -1;
          next = -1;
        }

        data.index = code === 40 ? next : prev; // Update HTML

        data.$list.removeClass("autocompleter-item-selected");

        if (data.index !== -1) {
          data.$list.eq(data.index).addClass("autocompleter-item-selected");
        }

        data.$selected = data.$autocompleter.find(".autocompleter-item-selected").length ? data.$autocompleter.find(".autocompleter-item-selected") : null;

        if (data.changeWhenSelect) {
          _setValue(data);
        }
      }
    } else if ($.inArray(code, ignoredKeyCode) === -1 && $.inArray(code, data.ignoredKeyCode) === -1) {
      // Typing
      _launch(data);
    }
  }
  /**
   * @method private
   * @name _onKeydown
   * @description Keydown events in node, up/down for prevent cursor moving and right arrow for hint
   * @param e [object] "Event data"
   */


  function _onKeydown(e) {
    var data = e.data,
        code = e.keyCode ? e.keyCode : e.which;

    if (code === 40 || code === 38) {
      e.preventDefault();
      e.stopPropagation();
    } else if (code === 39) {
      // Right arrow
      if (data.hint && data.hintText && data.$autocompleter.find(".autocompleter-hint").hasClass("autocompleter-hint-show")) {
        e.preventDefault();
        e.stopPropagation();
        var hintOrigin = data.$autocompleter.find(".autocompleter-item").length ? data.$autocompleter.find(".autocompleter-item").eq(0).attr("data-label") : false;

        if (hintOrigin) {
          data.query = hintOrigin;

          _setHint(data);
        }
      }
    } else if (code === 13) {
      // Enter
      if (data.$autocompleter.hasClass("autocompleter-show") && data.$selected) {
        _select(e);
      }
    }
  }
  /**
   * @method private
   * @name _onFocus
   * @description Handles instance focus
   * @param e [object] "Event data"
   * @param internal [boolean] "Called by plugin"
   */


  function _onFocus(e, internal) {
    if (!internal) {
      var data = e.data;
      data.$autocompleter.addClass("autocompleter-focus");

      if (!data.$node.prop("disabled") && !data.$autocompleter.hasClass("autocompleter-show")) {
        if (data.focusOpen) {
          _launch(data);

          data.focused = true;
          setTimeout(function () {
            data.focused = false;
          }, 500);
        }
      }
    }
  }
  /**
   * @method private
   * @name _onBlur
   * @description Handles instance blur
   * @param e [object] "Event data"
   * @param internal [boolean] "Called by plugin"
   */


  function _onBlur(e, internal) {
    e.preventDefault();
    e.stopPropagation();
    var data = e.data;

    if (!internal) {
      data.$autocompleter.removeClass("autocompleter-focus");

      _close(e);
    }
  }
  /**
   * @method private
   * @name _onMousedown
   * @description Handles mousedown to node
   * @param e [object] "Event data"
   */


  function _onMousedown(e) {
    // Disable middle & right mouse click
    if (e.type === "mousedown" && $.inArray(e.which, [2, 3]) !== -1) {
      return;
    }

    var data = e.data;

    if (data.$list && !data.focused) {
      if (!data.$node.is(":disabled")) {
        if (isMobile && !isFirefoxMobile) {
          var el = data.$select[0];

          if (window.document.createEvent) {
            // All
            var evt = window.document.createEvent("MouseEvents");
            evt.initMouseEvent("mousedown", false, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
            el.dispatchEvent(evt);
          } else if (el.fireEvent) {
            // IE
            el.fireEvent("onmousedown");
          }
        } else {
          // Delegate intent
          if (data.$autocompleter.hasClass("autocompleter-closed")) {
            _open(e);
          } else if (data.$autocompleter.hasClass("autocompleter-show")) {
            _close(e);
          }
        }
      }
    }
  }
  /**
   * @method private
   * @name _open
   * @description Opens option set
   * @param e [object] "Event data"
   * @param instanceData [object] "Instance data"
   */


  function _open(e, instanceData) {
    var data = e ? e.data : instanceData;

    if (!data.$node.prop("disabled") && !data.$autocompleter.hasClass("autocompleter-show") && data.$list && data.$list.length) {
      data.$autocompleter.removeClass("autocompleter-closed").addClass("autocompleter-show");
      $body.on("click.autocompleter-" + data.guid, ":not(.autocompleter-item)", data, _closeHelper);
    }
  }
  /**
   * @method private
   * @name _closeHelper
   * @description Determines if event target is outside instance before closing
   * @param e [object] "Event data"
   */


  function _closeHelper(e) {
    if ($(e.target).hasClass("autocompleter-node")) {
      return;
    }

    if ($(e.currentTarget).parents(".autocompleter").length === 0) {
      _close(e);
    }
  }
  /**
   * @method private
   * @name _close
   * @description Closes option set
   * @param e [object] "Event data"
   * @param instanceData [object] "Instance data"
   */


  function _close(e, instanceData) {
    var data = e ? e.data : instanceData;

    if (data.$autocompleter.hasClass("autocompleter-show")) {
      data.$autocompleter.removeClass("autocompleter-show").addClass("autocompleter-closed");
      $body.off(".autocompleter-" + data.guid);
    }
  }
  /**
   * @method private
   * @name _select
   * @description Select item from .autocompleter-list
   * @param e [object] "Event data"
   */


  function _select(e) {
    // Disable middle & right mouse click
    if (e.type === "mousedown" && $.inArray(e.which, [2, 3]) !== -1) {
      return;
    }

    var data = e.data;
    e.preventDefault();
    e.stopPropagation();

    if (e.type === "mousedown" && $(this).length) {
      data.$selected = $(this);
      data.index = data.$list.index(data.$selected);
    }

    if (!data.$node.prop("disabled")) {
      _close(e);

      _update(data);

      if (e.type === "click") {
        data.$node.trigger("focus", [true]);
      }
    }
  }
  /**
   * @method private
   * @name _setHint
   * @description Set autocompleter by hint
   * @param data [object] "Instance data"
   */


  function _setHint(data) {
    _setValue(data);

    _handleChange(data);

    _launch(data);
  }
  /**
   * @method private
   * @name _setValue
   * @description Set value for native field
   * @param data [object] "Instance data"
   */


  function _setValue(data) {
    if (data.$selected) {
      if (data.hintText && data.$autocompleter.find(".autocompleter-hint").hasClass("autocompleter-hint-show")) {
        data.$autocompleter.find(".autocompleter-hint").removeClass("autocompleter-hint-show");
      }

      data.$node.val(data.$selected.attr("data-value") ? data.$selected.attr("data-value") : data.$selected.attr("data-label"));
    } else {
      if (data.hintText && !data.$autocompleter.find(".autocompleter-hint").hasClass("autocompleter-hint-show")) {
        data.$autocompleter.find(".autocompleter-hint").addClass("autocompleter-hint-show");
      }

      data.$node.val(data.query);
    }
  }
  /**
   * @method private
   * @name _update
   * @param data [object] "Instance data"
   */


  function _update(data) {
    _setValue(data);

    _handleChange(data);

    _clear(data);
  }
  /**
   * @method private
   * @name _handleChange
   * @description Trigger node change event and call the callback function
   * @param data [object] "Instance data"
   */


  function _handleChange(data) {
    data.callback.call(data.$autocompleter, data.$node.val(), data.index, data.response[data.index]);
    data.$node.trigger("change");
  }
  /**
   * @method private
   * @name _grab
   * @description Grab sub-object from object
   * @param response [object] "Native object"
   * @param offset [string] "Offset string"
   */


  function _grab(response, offset) {
    offset = offset.split(".");

    while (response && offset.length) {
      response = response[offset.shift()];
    }

    return response;
  }
  /**
   * @method private
   * @name _setCache
   * @description Store AJAX response in plugin cache
   * @param url [string] "AJAX get query string"
   * @param data [object] "AJAX response data"
   */


  function _setCache(url, data) {
    if (!supportLocalStorage) {
      return;
    }

    if (url && data) {
      cache[url] = {
        value: data,
        timestamp: +new Date()
      }; // Proccess to localStorage

      try {
        localStorage.setItem(localStorageKey, JSON.stringify(cache));
      } catch (e) {
        var code = e.code || e.number || e.message;

        if (code === 22) {
          _deleteCache();
        } else {
          throw e;
        }
      }
    }
  }
  /**
   * @method private
   * @name _getCache
   * @description Get cached data by url if exist
   * @param url [string] "AJAX get query string"
   */


  function _getCache(url, expires) {
    var response = false,
        item;
    expires = expires || false;

    if (!url) {
      return false;
    }

    item = cache[url];

    if (item && item.value) {
      response = item.value;

      if (item.timestamp && expires && +new Date() - item.timestamp > expires * 1000) {
        return false;
      } else {
        return response;
      }
    } else {
      return false;
    }
  }
  /**
   * @method private
   * @name _loadCache
   * @description Load all plugin cache from localStorage
   */


  function _loadCache() {
    if (!supportLocalStorage) {
      return;
    }

    return JSON.parse(localStorage.getItem(localStorageKey) || "{}");
  }
  /**
   * @method private
   * @name _deleteCache
   * @description Delete all plugin cache from localStorage
   */


  function _deleteCache() {
    try {
      localStorage.removeItem(localStorageKey);
      cache = _loadCache();
    } catch (e) {//
    }
  }
  /**
   * @method private
   * @name _clone
   * @description Clone JavaScript object
   */


  function _clone(obj) {
    var copy;

    if (null === obj || "object" !== _typeof(obj)) {
      return obj;
    }

    copy = obj.constructor();

    for (var attr in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, attr)) {
        copy[attr] = obj[attr];
      }
    }

    return copy;
  } // Load cache


  var cache = _loadCache();

  $.fn.autocompleter = function (method) {
    if (publics[method]) {
      return publics[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (_typeof(method) === "object" || !method) {
      return _init.apply(this, arguments);
    }

    return this;
  };

  $.autocompleter = function (method) {
    if (method === "defaults") {
      publics.defaults.apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (method === "clearCache") {
      publics.clearCache.apply(this, null);
    }
  };

})));
