text: define([
      'dojo/_base/declare',
      'dojo/_base/array',
      'dojo/dom-construct',
      'dojo/on',
      'dojo/aspect',
      'dijit/Dialog',
      'dijit/form/Button',
      'dijit/form/TextBox',
      'dijit/focus',
      'JBrowse/View/LocationList',
      'JBrowse/Util'
  ],
  function (
      declare,
      array,
      dom,
      on,
      aspect,
      Dialog,
      Button,
      TextBox,
      dijitFocus,
      LocationListView,
      Util
  ) {
      return declare(null, {
          constructor: function (args) {
              this.browser = args.browser;
              this.config = dojo.clone(args.config || {});
              this.locationChoices = [{label: 'Search results...', description: ' ', start: 0, end: 100, ref: 'chr'}];
              this.title = args.title || 'Choose location';
              this.prompt = args.prompt || 'Search for features';
              this.goCallback = args.goCallback;
              this.showCallback = args.showCallback;
          },
  
          show: function () {
              var dialog = this.dialog = new Dialog({
                  title: this.title,
                  className: 'locationChoiceDialog',
                  style: { width: '70%' }
              });
              var container = dom.create('div', {});
  
              if (this.prompt) {
                  dom.create('div', {
                      className: 'prompt',
                      innerHTML: this.prompt
                  }, container);
                  var subcontainer = dojo.create('div', { style: { 'padding': '20px' } }, container);
                  dojo.create('img', { width: '16px', src: 'img/search.png', style: { 'padding-right': '5px' } }, subcontainer);
                  this.searchBox = new TextBox({intermediateChanges: true}).placeAt(subcontainer);
                  dojo.create('label', {style: {marginLeft: '20px'}, for: 'exact_match', innerHTML: 'Exact?'}, subcontainer);
                  this.exactCheckbox = dojo.create('input', {type: 'checkbox', id: 'exact_match'}, subcontainer);
  
                  on(this.searchBox, 'change', dojo.hitch(this, 'searchBoxProcess'));
                  on(this.exactCheckbox, 'change', dojo.hitch(this, 'searchBoxProcess'));
              }
              var browser = this.browser;
              this.locationListView = new LocationListView(
                  {
                      browser: browser,
                      locations: this.locationChoices,
                      buttons: [{
                          className: 'show',
                          innerHTML: 'Show',
                          onClick: this.showCallback || function (location) {
                              browser.showRegionAfterSearch(location);
                          }
                      },
                      {
                          className: 'go',
                          innerHTML: 'Go',
                          onClick: this.goCallback   || function (location) {
                              dialog.hide();
                              browser.showRegionAfterSearch(location);
                          }
                      }]
                  },
                  dom.create('div', {
                      className: 'locationList',
                      style: { maxHeight: 0.5 * this.browser.container.offsetHeight + 'px'}
                  }, container)
              );
  
  
              this.actionBar = dojo.create('div', { className: 'infoDialogActionBar dijitDialogPaneActionBar' });
              new Button({
                  iconClass: 'dijitIconDelete',
                  label: 'Cancel',
                  onClick: dojo.hitch(dialog, 'hide')
              }).placeAt(this.actionBar);
  
              this.numResults = dojo.create('div', { id: 'numResults', style: {margin: '10px'} }, container);
              this.errResults = dojo.create('div', { id: 'errResults', style: {margin: '10px', color: 'red'} }, container);
              dialog.set('content', [ container, this.actionBar ]);
  
              var g = this.locationListView.grid;
              (g.store || g.collection).setData([]);
              g.refresh();
              dialog.show();
  
              aspect.after(dialog, 'hide', dojo.hitch(this, function () {
                  if (dijitFocus.curNode) {
                      dijitFocus.curNode.blur();
                  }
                  setTimeout(function () {
                      dialog.destroyRecursive();
                  }, 500);
              }));
          },
          searchBoxProcess: function() {
              var loc = this.searchBox.get('value');
              this.numResults.innerHTML = '';
              if (!this.exactCheckbox.checked) {
                  loc += "*";
              }
              function handleError(error) {
                  console.error(error);
                  var g = this.locationListView.grid;
                  (g.store || g.collection).setData([]);
                  g.refresh();
                  this.errResults.innerHTML = 'Error: failed to load results';
                  this.numResults.innerHTML = '';
              }
              this.browser.nameStore.query({ name: loc }).then((nameMatches) => {
                  var promises = nameMatches.map((match) => this.browser.nameStore.query({ name: match.name }));
                  Promise.all(promises).then((res) => {
                      var grid = [];
                      for(var i = 0; i < res.length; i++) {
                          var elt = res[i];
                          if(elt.length) {
                              elt = elt[0];
                              if(elt.multipleLocations) {
                                  for(var j = 0; j < elt.multipleLocations.length; j++) {
                                      var track = elt.multipleLocations[j].tracks.length ? elt.multipleLocations[j].tracks[0] : {};
                                      grid.push({
                                          locstring: Util.assembleLocString(elt.multipleLocations[j]),
                                          location: elt.multipleLocations[j],
                                          label: elt.name,
                                          description: track.key || track.label || 'Unknown track',
                                          tracks: track
                                      });
                                  }
                              } else {
                                  var track = (elt.location.tracks||[]).length ? elt.location.tracks[0] : {};
                                  grid.push({
                                      locstring: Util.assembleLocString(elt.location),
                                      location: elt.location,
                                      label: elt.location.objectName,
                                      description: track.key || track.label || 'Unknown track',
                                      tracks: track
                                  });
                              }
                          }
                      }
                      this.numResults.innerHTML = "Num. results: " + grid.length;
                      var g = this.locationListView.grid;
                      (g.store || g.collection).setData(grid);
                      g.refresh();
                      this.errResults.innerHTML = '';
                  }, dojo.hitch(this, handleError));
              }, dojo.hitch(this, handleError));
          }
      });
  });
  