whole_func_string: function (opts) {
              var element, select, idKey, ajaxUrl, self = this;
  
              element = opts.element;
  
              if (element.get(0).tagName.toLowerCase() === "select") {
                  this.select = select = opts.element;
              }
  
              if (select) {
                  // these options are not allowed when attached to a select because they are picked up off the element itself
                  $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () {
                      if (this in opts) {
                          throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element.");
                      }
                  });
              }
  
              opts = $.extend({}, {
                  populateResults: function(container, results, query) {
                      var populate,  data, result, children, id=this.opts.id;
  
                      populate=function(results, container, depth) {
  
                          var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted;
  
                          results = opts.sortResults(results, container, query);
  
                          for (i = 0, l = results.length; i < l; i = i + 1) {
  
                              result=results[i];
  
                              disabled = (result.disabled === true);
                              selectable = (!disabled) && (id(result) !== undefined);
  
                              compound=result.children && result.children.length > 0;
  
                              node=$("<li></li>");
                              node.addClass("select2-results-dept-"+depth);
                              node.addClass("select2-result");
                              node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
                              if (disabled) { node.addClass("select2-disabled"); }
                              if (compound) { node.addClass("select2-result-with-children"); }
                              node.addClass(self.opts.formatResultCssClass(result));
  
                              label=$(document.createElement("div"));
                              label.addClass("select2-result-label");
  
                              formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup);
                              if (formatted!==undefined) {
                                  label.html(formatted);
                              }
  
                              node.append(label);
  
                              if (compound) {
  
                                  innerContainer=$("<ul></ul>");
                                  innerContainer.addClass("select2-result-sub");
                                  populate(result.children, innerContainer, depth+1);
                                  node.append(innerContainer);
                              }
  
                              node.data("select2-data", result);
                              container.append(node);
                          }
                      };
  
                      populate(results, container, 0);
                  }
              }, $.fn.select2.defaults, opts);
  
              if (typeof(opts.id) !== "function") {
                  idKey = opts.id;
                  opts.id = function (e) { return e[idKey]; };
              }
  
              if ($.isArray(opts.element.data("select2Tags"))) {
                  if ("tags" in opts) {
                      throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id");
                  }
                  opts.tags=opts.element.data("select2Tags");
              }
  
              if (select) {
                  opts.query = this.bind(function (query) {
                      var data = { results: [], more: false },
                          term = query.term,
                          children, placeholderOption, process;
  
                      process=function(element, collection) {
                          var group;
                          if (element.is("option")) {
                              if (query.matcher(term, element.text(), element)) {
                                  collection.push(self.optionToData(element));
                              }
                          } else if (element.is("optgroup")) {
                              group=self.optionToData(element);
                              element.children().each2(function(i, elm) { process(elm, group.children); });
                              if (group.children.length>0) {
                                  collection.push(group);
                              }
                          }
                      };
  
                      children=element.children();
  
                      // ignore the placeholder option if there is one
                      if (this.getPlaceholder() !== undefined && children.length > 0) {
                          placeholderOption = this.getPlaceholderOption();
                          if (placeholderOption) {
                              children=children.not(placeholderOption);
                          }
                      }
  
                      children.each2(function(i, elm) { process(elm, data.results); });
  
                      query.callback(data);
                  });
                  // this is needed because inside val() we construct choices from options and there id is hardcoded
                  opts.id=function(e) { return e.id; };
                  opts.formatResultCssClass = function(data) { return data.css; };
              } else {
                  if (!("query" in opts)) {
  
                      if ("ajax" in opts) {
                          ajaxUrl = opts.element.data("ajax-url");
                          if (ajaxUrl && ajaxUrl.length > 0) {
                              opts.ajax.url = ajaxUrl;
                          }
                          opts.query = ajax.call(opts.element, opts.ajax);
                      } else if ("data" in opts) {
                          opts.query = local(opts.data);
                      } else if ("tags" in opts) {
                          opts.query = tags(opts.tags);
                          if (opts.createSearchChoice === undefined) {
                              opts.createSearchChoice = function (term) { return {id: term, text: term}; };
                          }
                          if (opts.initSelection === undefined) {
                              opts.initSelection = function (element, callback) {
                                  var data = [];
                                  $(splitVal(element.val(), opts.separator)).each(function () {
                                      var id = this, text = this, tags=opts.tags;
                                      if ($.isFunction(tags)) tags=tags();
                                      $(tags).each(function() { if (equal(this.id, id)) { text = this.text; return false; } });
                                      data.push({id: id, text: text});
                                  });
  
                                  callback(data);
                              };
                          }
                      }
                  }
              }
              if (typeof(opts.query) !== "function") {
                  throw "query function not defined for Select2 " + opts.element.attr("id");
              }
  
              return opts;
          }
func_code_string: function (opts) {
              var element, select, idKey, ajaxUrl, self = this;
  
              element = opts.element;
  
              if (element.get(0).tagName.toLowerCase() === "select") {
                  this.select = select = opts.element;
              }
  
              if (select) {
                  // these options are not allowed when attached to a select because they are picked up off the element itself
                  $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () {
                      if (this in opts) {
                          throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element.");
                      }
                  });
              }
  
              opts = $.extend({}, {
                  populateResults: function(container, results, query) {
                      var populate,  data, result, children, id=this.opts.id;
  
                      populate=function(results, container, depth) {
  
                          var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted;
  
                          results = opts.sortResults(results, container, query);
  
                          for (i = 0, l = results.length; i < l; i = i + 1) {
  
                              result=results[i];
  
                              disabled = (result.disabled === true);
                              selectable = (!disabled) && (id(result) !== undefined);
  
                              compound=result.children && result.children.length > 0;
  
                              node=$("<li></li>");
                              node.addClass("select2-results-dept-"+depth);
                              node.addClass("select2-result");
                              node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
                              if (disabled) { node.addClass("select2-disabled"); }
                              if (compound) { node.addClass("select2-result-with-children"); }
                              node.addClass(self.opts.formatResultCssClass(result));
  
                              label=$(document.createElement("div"));
                              label.addClass("select2-result-label");
  
                              formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup);
                              if (formatted!==undefined) {
                                  label.html(formatted);
                              }
  
                              node.append(label);
  
                              if (compound) {
  
                                  innerContainer=$("<ul></ul>");
                                  innerContainer.addClass("select2-result-sub");
                                  populate(result.children, innerContainer, depth+1);
                                  node.append(innerContainer);
                              }
  
                              node.data("select2-data", result);
                              container.append(node);
                          }
                      };
  
                      populate(results, container, 0);
                  }
              }, $.fn.select2.defaults, opts);
  
              if (typeof(opts.id) !== "function") {
                  idKey = opts.id;
                  opts.id = function (e) { return e[idKey]; };
              }
  
              if ($.isArray(opts.element.data("select2Tags"))) {
                  if ("tags" in opts) {
                      throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id");
                  }
                  opts.tags=opts.element.data("select2Tags");
              }
  
              if (select) {
                  opts.query = this.bind(function (query) {
                      var data = { results: [], more: false },
                          term = query.term,
                          children, placeholderOption, process;
  
                      process=function(element, collection) {
                          var group;
                          if (element.is("option")) {
                              if (query.matcher(term, element.text(), element)) {
                                  collection.push(self.optionToData(element));
                              }
                          } else if (element.is("optgroup")) {
                              group=self.optionToData(element);
                              element.children().each2(function(i, elm) { process(elm, group.children); });
                              if (group.children.length>0) {
                                  collection.push(group);
                              }
                          }
                      };
  
                      children=element.children();
  
                      // ignore the placeholder option if there is one
                      if (this.getPlaceholder() !== undefined && children.length > 0) {
                          placeholderOption = this.getPlaceholderOption();
                          if (placeholderOption) {
                              children=children.not(placeholderOption);
                          }
                      }
  
                      children.each2(function(i, elm) { process(elm, data.results); });
  
                      query.callback(data);
                  });
                  // this is needed because inside val() we construct choices from options and there id is hardcoded
                  opts.id=function(e) { return e.id; };
                  opts.formatResultCssClass = function(data) { return data.css; };
              } else {
                  if (!("query" in opts)) {
  
                      if ("ajax" in opts) {
                          ajaxUrl = opts.element.data("ajax-url");
                          if (ajaxUrl && ajaxUrl.length > 0) {
                              opts.ajax.url = ajaxUrl;
                          }
                          opts.query = ajax.call(opts.element, opts.ajax);
                      } else if ("data" in opts) {
                          opts.query = local(opts.data);
                      } else if ("tags" in opts) {
                          opts.query = tags(opts.tags);
                          if (opts.createSearchChoice === undefined) {
                              opts.createSearchChoice = function (term) { return {id: term, text: term}; };
                          }
                          if (opts.initSelection === undefined) {
                              opts.initSelection = function (element, callback) {
                                  var data = [];
                                  $(splitVal(element.val(), opts.separator)).each(function () {
                                      var id = this, text = this, tags=opts.tags;
                                      if ($.isFunction(tags)) tags=tags();
                                      $(tags).each(function() { if (equal(this.id, id)) { text = this.text; return false; } });
                                      data.push({id: id, text: text});
                                  });
  
                                  callback(data);
                              };
                          }
                      }
                  }
              }
              if (typeof(opts.query) !== "function") {
                  throw "query function not defined for Select2 " + opts.element.attr("id");
              }
  
              return opts;
          }
func_documentation_string: abstract