define([
  'jquery'
], function ($) {
  function Tags (decorated, $element, options) {
    var tags = options.get('tags');
    var createTag = options.get('createTag');
    if (createTag !== undefined) {
      this.createTag = createTag;
    }
    var insertTag = options.get('insertTag');
    if (insertTag !== undefined) {
        this.insertTag = insertTag;
    }
    decorated.call(this, $element, options);
    if ($.isArray(tags)) {
      for (var t = 0; t < tags.length; t++) {
        var tag = tags[t];
        var item = this._normalizeItem(tag);
        var $option = this.option(item);
        this.$element.append($option);
      }
    }
  }
  Tags.prototype.query = function (decorated, params, callback) {
    var self = this;
    this._removeOldTags();
    if (params.term == null || params.page != null) {
      decorated.call(this, params, callback);
      return;
    }
    function wrapper (obj, child) {
      var data = obj.results;
      for (var i = 0; i < data.length; i++) {
        var option = data[i];
        var checkChildren = (
          option.children != null &&
          !wrapper({
            results: option.children
          }, true)
        );
        var checkText = option.text === params.term;
        if (checkText || checkChildren) {
          if (child) {
            return false;
          }
          obj.data = data;
          callback(obj);
          return;
        }
      }
      if (child) {
        return true;
      }
      var tag = self.createTag(params);
      if (tag != null) {
        var $option = self.option(tag);
        $option.attr('data-select2-tag', true);
        self.addOptions([$option]);
        self.insertTag(data, tag);
      }
      obj.results = data;
      callback(obj);
    }
    decorated.call(this, params, wrapper);
  };
  Tags.prototype.createTag = function (decorated, params) {
    var term = $.trim(params.term);
    if (term === '') {
      return null;
    }
    return {
      id: term,
      text: term
    };
  };
  Tags.prototype.insertTag = function (_, data, tag) {
    data.unshift(tag);
  };
  Tags.prototype._removeOldTags = function (_) {
    var tag = this._lastTag;
    var $options = this.$element.find('option[data-select2-tag]');
    $options.each(function () {
      if (this.selected) {
        return;
      }
      $(this).remove();
    });
  };
  return Tags;
});
 
  |