text: /*======================================================================
   *  Exhibit
   *  http://simile.mit.edu/wiki/Exhibit/API/Exhibit
   *======================================================================
   */
   
  Exhibit.create = function(database) {
      return new Exhibit._Impl(database);
  };
  
  Exhibit.getAttribute = function(elmt, name, splitOn) {
      try {
          var value = elmt.getAttribute(name);
          if (value == null || value.length == 0) {
              value = elmt.getAttribute("ex:" + name);
              if (value != null && value.length == 0) {
                  return null;
              }
          }
          if (splitOn == null) {
              return value;
          }
          var values = value.split(splitOn);
          for (var i = 0; value = values[i]; i++) {
              values[i] = value.trim();
          }
          return values;
      } catch(e) { 
          return null;
      }
  };
  
  Exhibit.getRoleAttribute = function(elmt) {
      var role = Exhibit.getAttribute(elmt, "role") || "";
      role = role.replace(/^exhibit-/, "");
      return role;
  };
  
  Exhibit.getConfigurationFromDOM = function(elmt) {
      var c = Exhibit.getAttribute(elmt, "configuration");
      if (c != null && c.length > 0) {
          try{
              var o = eval(c);
              if (typeof o == "object") {
                  return o;
              }
          } catch (e) {}
      }
      return {};
  };
  
  Exhibit.extractOptionsFromElement = function(elmt) {
      var opts = {};
      var attrs = elmt.attributes;
      for (var i in attrs) {
          if (attrs.hasOwnProperty(i)) {
              var name = attrs[i].nodeName;
              var value = attrs[i].nodeValue;
              if (name.indexOf('ex:') == 0) {
                  name = name.substring(3);
              }
              opts[name] = value;
          }
      }
      return opts;
  }
  
  Exhibit.getExporters = function() {
      Exhibit._initializeExporters();
      return [].concat(Exhibit._exporters);
  };
  
  Exhibit.addExporter = function(exporter) {
      Exhibit._initializeExporters();
      Exhibit._exporters.push(exporter);
  };
  
  Exhibit._initializeExporters = function() {
      if (!("_exporters" in Exhibit)) {
          Exhibit._exporters = [
              Exhibit.RdfXmlExporter,
              Exhibit.SemanticWikitextExporter,
              Exhibit.TSVExporter,
              Exhibit.ExhibitJsonExporter,
              Exhibit.FacetSelectionExporter
          ];
      }
  };
  
  /*==================================================
   *  Exhibit._Impl
   *==================================================
   */
  Exhibit._Impl = function(database) {
      this._database = database != null ? 
          database : 
          ("database" in window ?
              window.database :
              Exhibit.Database.create());
              
      this._uiContext = Exhibit.UIContext.createRootContext({}, this);
      this._collectionMap = {};
      this._componentMap= {};
      
      this._historyListener = {
          onBeforePerform:        function(action) { if(action.lengthy) { Exhibit.UI.showBusyIndicator();} },
          onAfterPerform:         function(action) { if(action.lengthy) { Exhibit.UI.hideBusyIndicator();} },
          onBeforeUndoSeveral:    function() { Exhibit.UI.showBusyIndicator();},
          onAfterUndoSeveral:     function() { Exhibit.UI.hideBusyIndicator();},
          onBeforeRedoSeveral:    function() { Exhibit.UI.showBusyIndicator();},
          onAfterRedoSeveral:     function() { Exhibit.UI.hideBusyIndicator();}
      };
      SimileAjax.History.addListener(this._historyListener);    
  };
  
  Exhibit._Impl.prototype.dispose = function() {
      SimileAjax.History.removeListener(this._historyListener);
      
      for (var id in this._componentMap) {
          try{
              this._componentMap[id].dispose();
          }catch(e) {
              SimileAjax.Debug.exception(e, "Failed to dispose component");
          }
      }
      for (var id in this._collectionMap) {
          try{
              this._collectionMap[id].dispose();
          } catch(e) {
              SimileAjax.Debug.exception(e, "Failed to dispose collection");
          }
      }
      
      this._uiContext.dispose();
      
      this._componentMap = null;
      this._collectionMap = null;
      this._uiContext = null;
      this._database = null;
  };
  
  Exhibit._Impl.prototype.getDatabase = function() {
      return this._database;
  };
  
  Exhibit._Impl.prototype.getUIContext = function() {
      return this._uiContext;
  };
  
  Exhibit._Impl.prototype.getCollection = function(id) {
      var collection = this._collectionMap[id];
      if (collection == null && id == "default") {
          collection = Exhibit.Collection.createAllItemsCollection(id, this._database);
          this.setDefaultCollection(collection);
      }
      return collection;
  };
  
  Exhibit._Impl.prototype.getDefaultCollection = function() {
      return this.getCollection("default");
  };
  
  Exhibit._Impl.prototype.setCollection = function(id, c) {
      if (id in this._collectionMap) {
          try{
              this._collectionMap[id].dispose();
          } catch(e) {
              SimileAjax.Debug.exception(e);
          }
      }
      this._collectionMap[id] = c;
  };
  
  Exhibit._Impl.prototype.setDefaultCollection = function(c) {
      this.setCollection("default", c);
  };
  
  Exhibit._Impl.prototype.getComponent = function(id) {
      return this._componentMap[id];
  };
  
  Exhibit._Impl.prototype.setComponent = function(id, c) {
      if (id in this._componentMap) {
          try{
              this._componentMap[id].dispose();
          } catch(e) {
              SimileAjax.Debug.exception(e);
          }
      }
      
      this._componentMap[id] = c;
  };
  
  Exhibit._Impl.prototype.disposeComponent = function(id) {
      if (id in this._componentMap) {
          try{
              this._componentMap[id].dispose();
          } catch(e) {
              SimileAjax.Debug.exception(e);
          }
          delete this._componentMap[id];
      }
  };
  
  Exhibit._Impl.prototype.configure = function(configuration) {
      if ("collections" in configuration) {
          for (var i = 0; i < configuration.collections.length; i++) {
              var config = configuration.collections[i];
              var id = config.id;
              if (id == null || id.length == 0) {
                  id = "default";
              }
              this.setCollection(id, Exhibit.Collection.create2(id, config, this._uiContext));
          }
      }
      if ("components" in configuration) {
          for (var i = 0; i < configuration.components.length; i++) {
              var config = configuration.components[i];
              var component = Exhibit.UI.create(config, config.elmt, this._uiContext);
              if (component != null) {
                  var id = elmt.id;
                  if (id == null || id.length == 0) {
                      id = "component" + Math.floor(Math.random() * 1000000);
                  }
                  this.setComponent(id, component);
              }
          }
      }
  };
  
  /**
   * Set up this Exhibit's view from its DOM configuration.
   * @param {Node} root  optional root node, below which configuration gets read
   *                     (defaults to document.body, when none provided)
   */
  Exhibit._Impl.prototype.configureFromDOM = function(root) {
      var collectionElmts = [];
      var coderElmts = [];
      var coordinatorElmts = [];
      var lensElmts = [];
      var facetElmts = [];
      var otherElmts = [];
      var f = function(elmt) {
          var role = Exhibit.getRoleAttribute(elmt);
          if (role.length > 0) {
              switch (role) {
              case "collection":  collectionElmts.push(elmt); break;
              case "coder":       coderElmts.push(elmt); break;
              case "coordinator": coordinatorElmts.push(elmt); break;
              case "lens":
              case "submission-lens":
              case "edit-lens":   lensElmts.push(elmt); break;
              case "facet":       facetElmts.push(elmt); break;
              default: 
                  otherElmts.push(elmt);
              }
          } else {
              var node = elmt.firstChild;
              while (node != null) {
                  if (node.nodeType == 1) {
                      f(node);
                  }
                  node=node.nextSibling;
              }
          }
      };
      f(root || document.body);
      
      var uiContext = this._uiContext;
      for (var i = 0; i < collectionElmts.length; i++) {
          var elmt = collectionElmts[i];
          var id = elmt.id;
          if (id == null || id.length == 0) {
              id = "default";
          }
          this.setCollection(id, Exhibit.Collection.createFromDOM2(id, elmt, uiContext));
      }
      
      var self = this;
      var processElmts = function(elmts) {
          for (var i = 0; i < elmts.length; i++) {
              var elmt = elmts[i];
              try {
                  var component = Exhibit.UI.createFromDOM(elmt, uiContext);
                  if (component != null) {
                      var id = elmt.id;
                      if (id == null || id.length == 0) {
                          id = "component" + Math.floor(Math.random() * 1000000);
                      }
                      self.setComponent(id, component);
                  }
              } catch (e) {
                  SimileAjax.Debug.exception(e);
              }
          }
      };
      processElmts(coordinatorElmts);
      processElmts(coderElmts);
      processElmts(lensElmts);
      processElmts(facetElmts);
      processElmts(otherElmts);
      
      this.importSettings();
      
      var exporters = Exhibit.getAttribute(document.body, "exporters");
      if (exporters != null) {
          exporters = exporters.split(";");
          for (var i = 0; i < exporters.length; i++) {
              var expr = exporters[i];
              var exporter = null;
              
              try {
                  exporter = eval(expr);
              } catch (e) {}
              
              if (exporter == null) {
                  try { exporter = eval(expr + "Exporter"); } catch (e) {}
              }
              
              if (exporter == null) {
                  try { exporter = eval("Exhibit." + expr + "Exporter"); } catch (e) {}
              }
              
              if (typeof exporter == "object") {
                  Exhibit.addExporter(exporter);
              }
          }
      }
      
      var hash = document.location.hash;
      if (hash.length > 1) {
          var itemID = decodeURIComponent(hash.substr(1));
          if (this._database.containsItem(itemID)) {
              this._showFocusDialogOnItem(itemID);
          }
      }
  };
  
  Exhibit._Impl.prototype._showFocusDialogOnItem = function(itemID) {
      var dom = SimileAjax.DOM.createDOMFromString(
          "div",
          "<div class='exhibit-focusDialog-viewContainer' id='lensContainer'>" +
          "</div>" +
          "<div class='exhibit-focusDialog-controls'>" +
              "<button id='closeButton'>" + 
                  Exhibit.l10n.focusDialogBoxCloseButtonLabel + 
              "</button>" +
          "</div>"
      );
      dom.elmt.className = "exhibit-focusDialog exhibit-ui-protection";
      dom.close = function() {
          document.body.removeChild(dom.elmt);
      };
      dom.layer = SimileAjax.WindowManager.pushLayer(function() { dom.close(); }, false);
      
      var itemLens = this._uiContext.getLensRegistry().createLens(itemID, dom.lensContainer, this._uiContext);
      
      dom.elmt.style.top = (document.body.scrollTop + 100) + "px";
      document.body.appendChild(dom.elmt);
      
      SimileAjax.WindowManager.registerEvent(
          dom.closeButton, 
          "click", 
          function(elmt, evt, target) { SimileAjax.WindowManager.popLayer(dom.layer); },
          dom.layer
      );
  };
  
  Exhibit._Impl.prototype.exportSettings = function() {
    var facetSelections = {},
        facetSettings = '';
    for (var id in this._componentMap) {
      if (typeof this._componentMap[id].exportFacetSelection !== 'undefined') {
        facetSettings = this._componentMap[id].exportFacetSelection() || false;
        if (facetSettings) {
          facetSelections[id] = facetSettings;
        }
      }
    }
    return facetSelections;
  };
  
  Exhibit._Impl.prototype.importSettings = function() {
    if (window.location.search.length > 0) {
      searchComponents = window.location.search.substr(1, window.location.search.length-1).split('&');
      for(var x = 0; x < searchComponents.length; x++) {
        var component = searchComponents[x].split('=');
        var componentId = component[0];
        var componentSelection = unescape(component[1]);
        if (this._componentMap[componentId] && (typeof this._componentMap[componentId].importFacetSelection !== 'undefined')) {
          this._componentMap[componentId].importFacetSelection(componentSelection);
        }
      }
    }
  };