text: define([
    'jquery',
    'require',
  
    './results',
  
    './selection/single',
    './selection/multiple',
    './selection/placeholder',
    './selection/allowClear',
    './selection/search',
    './selection/eventRelay',
  
    './utils',
    './translation',
    './diacritics',
  
    './data/select',
    './data/array',
    './data/ajax',
    './data/tags',
    './data/tokenizer',
    './data/minimumInputLength',
    './data/maximumInputLength',
    './data/maximumSelectionLength',
  
    './dropdown',
    './dropdown/search',
    './dropdown/hidePlaceholder',
    './dropdown/infiniteScroll',
    './dropdown/attachBody',
    './dropdown/minimumResultsForSearch',
    './dropdown/selectOnClose',
    './dropdown/closeOnSelect',
  
    './i18n/en'
  ], function ($, require,
  
               ResultsList,
  
               SingleSelection, MultipleSelection, Placeholder, AllowClear,
               SelectionSearch, EventRelay,
  
               Utils, Translation, DIACRITICS,
  
               SelectData, ArrayData, AjaxData, Tags, Tokenizer,
               MinimumInputLength, MaximumInputLength, MaximumSelectionLength,
  
               Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
               AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,
  
               EnglishTranslation) {
    function Defaults () {
      this.reset();
    }
  
    Defaults.prototype.apply = function (options) {
      options = $.extend({}, this.defaults, options);
  
      if (options.dataAdapter == null) {
        if (options.ajax != null) {
          options.dataAdapter = AjaxData;
        } else if (options.data != null) {
          options.dataAdapter = ArrayData;
        } else {
          options.dataAdapter = SelectData;
        }
  
        if (options.minimumInputLength > 0) {
          options.dataAdapter = Utils.Decorate(
            options.dataAdapter,
            MinimumInputLength
          );
        }
  
        if (options.maximumInputLength > 0) {
          options.dataAdapter = Utils.Decorate(
            options.dataAdapter,
            MaximumInputLength
          );
        }
  
        if (options.maximumSelectionLength > 0) {
          options.dataAdapter = Utils.Decorate(
            options.dataAdapter,
            MaximumSelectionLength
          );
        }
  
        if (options.tags) {
          options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
        }
  
        if (options.tokenSeparators != null || options.tokenizer != null) {
          options.dataAdapter = Utils.Decorate(
            options.dataAdapter,
            Tokenizer
          );
        }
  
        if (options.query != null) {
          var Query = require(options.amdBase + 'compat/query');
  
          options.dataAdapter = Utils.Decorate(
            options.dataAdapter,
            Query
          );
        }
  
        if (options.initSelection != null) {
          var InitSelection = require(options.amdBase + 'compat/initSelection');
  
          options.dataAdapter = Utils.Decorate(
            options.dataAdapter,
            InitSelection
          );
        }
      }
  
      if (options.resultsAdapter == null) {
        options.resultsAdapter = ResultsList;
  
        if (options.ajax != null) {
          options.resultsAdapter = Utils.Decorate(
            options.resultsAdapter,
            InfiniteScroll
          );
        }
  
        if (options.placeholder != null) {
          options.resultsAdapter = Utils.Decorate(
            options.resultsAdapter,
            HidePlaceholder
          );
        }
  
        if (options.selectOnClose) {
          options.resultsAdapter = Utils.Decorate(
            options.resultsAdapter,
            SelectOnClose
          );
        }
      }
  
      if (options.dropdownAdapter == null) {
        if (options.multiple) {
          options.dropdownAdapter = Dropdown;
        } else {
          var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
  
          options.dropdownAdapter = SearchableDropdown;
        }
  
        if (options.minimumResultsForSearch !== 0) {
          options.dropdownAdapter = Utils.Decorate(
            options.dropdownAdapter,
            MinimumResultsForSearch
          );
        }
  
        if (options.closeOnSelect) {
          options.dropdownAdapter = Utils.Decorate(
            options.dropdownAdapter,
            CloseOnSelect
          );
        }
  
        options.dropdownAdapter = Utils.Decorate(
          options.dropdownAdapter,
          AttachBody
        );
      }
  
      if (options.selectionAdapter == null) {
        if (options.multiple) {
          options.selectionAdapter = MultipleSelection;
        } else {
          options.selectionAdapter = SingleSelection;
        }
  
        // Add the placeholder mixin if a placeholder was specified
        if (options.placeholder != null) {
          options.selectionAdapter = Utils.Decorate(
            options.selectionAdapter,
            Placeholder
          );
        }
  
        if (options.allowClear) {
          options.selectionAdapter = Utils.Decorate(
            options.selectionAdapter,
            AllowClear
          );
        }
  
        if (options.multiple) {
          options.selectionAdapter = Utils.Decorate(
            options.selectionAdapter,
            SelectionSearch
          );
        }
  
        options.selectionAdapter = Utils.Decorate(
          options.selectionAdapter,
          EventRelay
        );
      }
  
      if (typeof options.language === 'string') {
        // Check if the language is specified with a region
        if (options.language.indexOf('-') > 0) {
          // Extract the region information if it is included
          var languageParts = options.language.split('-');
          var baseLanguage = languageParts[0];
  
          options.language = [options.language, baseLanguage];
        } else {
          options.language = [options.language];
        }
      }
  
      if ($.isArray(options.language)) {
        var languages = new Translation();
        options.language.push('en');
  
        var languageNames = options.language;
  
        for (var l = 0; l < languageNames.length; l++) {
          var name = languageNames[l];
          var language = {};
  
          try {
            // Try to load it with the original name
            language = Translation.loadPath(name);
          } catch (e) {
            try {
              // If we couldn't load it, check if it wasn't the full path
              name = this.defaults.amdLanguageBase + name;
              language = Translation.loadPath(name);
            } catch (ex) {
              // The translation could not be loaded at all. Sometimes this is
              // because of a configuration problem, other times this can be
              // because of how Select2 helps load all possible translation files.
              if (options.debug && window.console && console.warn) {
                console.warn(
                  'Select2: The language file for "' + name + '" could not be ' +
                  'automatically loaded. A fallback will be used instead.'
                );
              }
  
              continue;
            }
          }
  
          languages.extend(language);
        }
  
        options.translations = languages;
      } else {
        options.translations = new Translation(options.language);
      }
  
      return options;
    };
  
    Defaults.prototype.reset = function () {
      function stripDiacritics (text) {
        // Used 'uni range + named function' from http://jsperf.com/diacritics/18
        function match(a) {
          return DIACRITICS[a] || a;
        }
  
        return text.replace(/[^\u0000-\u007E]/g, match);
      }
  
      function matcher (params, data) {
        // Always return the object if there is nothing to compare
        if ($.trim(params.term) === '') {
          return data;
        }
  
        // Do a recursive check for options with children
        if (data.children && data.children.length > 0) {
          // Clone the data object if there are children
          // This is required as we modify the object to remove any non-matches
          var match = $.extend(true, {}, data);
  
          // Check each child of the option
          for (var c = data.children.length - 1; c >= 0; c--) {
            var child = data.children[c];
  
            var matches = matcher(params, child);
  
            // If there wasn't a match, remove the object in the array
            if (matches == null) {
              match.children.splice(c, 1);
            }
          }
  
          // If any children matched, return the new object
          if (match.children.length > 0) {
            return match;
          }
  
          // If there were no matching children, check just the plain object
          return matcher(params, match);
        }
  
        var original = stripDiacritics(data.text).toUpperCase();
        var term = stripDiacritics(params.term).toUpperCase();
  
        // Check if the text contains the term
        if (original.indexOf(term) > -1) {
          return data;
        }
  
        // If it doesn't contain the term, don't return anything
        return null;
      }
  
      this.defaults = {
        amdBase: './',
        amdLanguageBase: './i18n/',
        closeOnSelect: true,
        debug: false,
        escapeMarkup: Utils.escapeMarkup,
        language: EnglishTranslation,
        matcher: matcher,
        minimumInputLength: 0,
        maximumInputLength: 0,
        maximumSelectionLength: 0,
        minimumResultsForSearch: 0,
        selectOnClose: false,
        sorter: function (data) {
          return data;
        },
        templateResult: function (result) {
          return result.text;
        },
        templateSelection: function (selection) {
          return selection.text;
        },
        theme: 'default',
        width: 'resolve'
      };
    };
  
    Defaults.prototype.set = function (key, value) {
      var camelKey = $.camelCase(key);
  
      var data = {};
      data[camelKey] = value;
  
      var convertedData = Utils._convertData(data);
  
      $.extend(this.defaults, convertedData);
    };
  
    var defaults = new Defaults();
  
    return defaults;
  });
  