text: define([
    'jquery'
  ], function ($) {
    function Tokenizer (decorated, $element, options) {
      var tokenizer = options.get('tokenizer');
  
      if (tokenizer !== undefined) {
        this.tokenizer = tokenizer;
      }
  
      decorated.call(this, $element, options);
    }
  
    Tokenizer.prototype.bind = function (decorated, container, $container) {
      decorated.call(this, container, $container);
  
      this.$search =  container.dropdown.$search || container.selection.$search ||
        $container.find('.select2-search__field');
    };
  
    Tokenizer.prototype.query = function (decorated, params, callback) {
      var self = this;
  
      function createAndSelect (data) {
        // Normalize the data object so we can use it for checks
        var item = self._normalizeItem(data);
  
        // Check if the data object already exists as a tag
        // Select it if it doesn't
        var $existingOptions = self.$element.find('option').filter(function () {
          return $(this).val() === item.id;
        });
  
        // If an existing option wasn't found for it, create the option
        if (!$existingOptions.length) {
          var $option = self.option(item);
          $option.attr('data-select2-tag', true);
  
          self._removeOldTags();
          self.addOptions([$option]);
        }
  
        // Select the item, now that we know there is an option for it
        select(item);
      }
  
      function select (data) {
        self.trigger('select', {
          data: data
        });
      }
  
      params.term = params.term || '';
  
      var tokenData = this.tokenizer(params, this.options, createAndSelect);
  
      if (tokenData.term !== params.term) {
        // Replace the search term if we have the search box
        if (this.$search.length) {
          this.$search.val(tokenData.term);
          this.$search.trigger('focus');
        }
  
        params.term = tokenData.term;
      }
  
      decorated.call(this, params, callback);
    };
  
    Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
      var separators = options.get('tokenSeparators') || [];
      var term = params.term;
      var i = 0;
  
      var createTag = this.createTag || function (params) {
        return {
          id: params.term,
          text: params.term
        };
      };
  
      while (i < term.length) {
        var termChar = term[i];
  
        if (separators.indexOf(termChar) === -1) {
          i++;
  
          continue;
        }
  
        var part = term.substr(0, i);
        var partParams = $.extend({}, params, {
          term: part
        });
  
        var data = createTag(partParams);
  
        if (data == null) {
          i++;
          continue;
        }
  
        callback(data);
  
        // Reset the term to not include the tokenized portion
        term = term.substr(i + 1) || '';
        i = 0;
      }
  
      return {
        term: term
      };
    };
  
    return Tokenizer;
  });
  