whole_func_string: function (golr_loc, golr_conf_obj, engine, mode){
      registry.call(this, ['prerun',
  			 'reset',
  			 'search',
  			 'error',
  			 'postrun']);
      this._is_a = 'bbop-manager-golr';
      var anchor = this; // get a good self-reference point
  
      // Per-manager logger.
      this._logger = new bbop.logger(this._is_a);
      //this._logger.DEBUG = true;
      this._logger.DEBUG = false;
      function ll(str){ anchor._logger.kvetch(str); }
  
      // Setup right handler subsystem--either returning a direct
      // response or a promise, depending.
      anchor._engine = engine || null;
      anchor._mode = mode || null;
      anchor._runner = function(resource, payload){
  	var ret = null;
  	// if( typeof(anchor._engine) === 'undefined' ){
  	//     throw new Error('"engine" not set in new bbop-manager-golr');
  	// }
  	if( anchor._mode === 'sync' ){
  	    ret = anchor._engine.fetch(resource, payload);
  	}else if( anchor._mode === 'async' ){
  	    ret = anchor._engine.start(resource, payload);
  	}else{
  	    // throw new Error('"mode" not set in new bbop-manager-golr');
  	    return resource;
  	}
  	return ret;
      };
  
      // The callback function called after a successful AJAX
      // intialization/reset call. First it runs some template code,
      // then it does all of the callbacks.
      anchor._run_reset_callbacks = function(response){
  	ll('run reset callbacks...');
  	//var response = new golr_response(json_data);
  	anchor.apply_callbacks('reset', [response, anchor]);
  	anchor.apply_callbacks('postrun', [response, anchor]);
      };
  
      // The main callback function called after a successful AJAX call in
      // the update function.
      anchor._run_search_callbacks = function(response){
  	ll('run search callbacks...');
  	//var response = new golr_response(json_data);
  	anchor.apply_callbacks('search', [response, anchor]);
  	anchor.apply_callbacks('postrun', [response, anchor]);
      };
  
      // This set is called when we run into a problem.
      anchor._run_error_callbacks = function(response){
  	ll('run error callbacks...');
  	//var response = new golr_response(json_data);
  	anchor.apply_callbacks('error', [response, anchor]);
  	anchor.apply_callbacks('postrun', [response, anchor]);
      };
  
      // The registries can only be applied if the engine is present.
      if( engine ){
  
  	// Re-contextualize run_promise_functions().
  	anchor.run_promise_functions = function(promise_function_stack, 
  						accumulator_function,
  						final_function,
  						error_function){
  	    // NOTE: Cannot sensibly use Function.call here as engine
  	    // is not really the superclass of this manager.
  	    return engine.run_promise_functions(promise_function_stack,
  						accumulator_function,
  						final_function,
  						error_function);
  	};
  
  	// Setup the appropriate callbacks in the engine for success.
  	anchor._engine.register('success', function(response){
  	    
      	    //console.log(anchor._engine);
      	    //console.log(response._raw);
  	    
              // 
              if( ! response.success() ){
  		throw new Error("Unsuccessful response from golr server!");
              }else{
  		var cb_type = response.callback_type();
  		//console.log('okay response from server, will probe type...: '+cb_type);
  		if( cb_type === 'reset' ){
                      anchor._run_reset_callbacks(response);
  		}else if( cb_type === 'search' ){
                      anchor._run_search_callbacks(response);
  		}else{
                      throw new Error("Unknown callback type (runner): "+cb_type);
  		}
              }
  	});
  	
  	// And, more easily, setup the appropriate callbacks in the
  	// engine for failure.
  	anchor._engine.register('error', function(response){
      	    anchor._run_error_callbacks(response);
  	});
  	
      }
  
      // Just want to compile these once.
      var alphanum = new RegExp(/^[a-zA-Z0-9 ]+$/);
  
      this.minimal_query_length = 3;
  
      // To help keep requests from the past haunting us. Actually doing
      // something with this number is up to the UI.
      this.last_sent_packet = 0;
      //this.last_received_packet = 0;
  
      // Lightly check incoming arguments.
      // There should be a string url argument.
      // There could be a hash of pinned filters argument.
      if( ! golr_loc || ! golr_conf_obj ){
  	ll('ERROR: no proper arguments');
      }
      if( typeof golr_loc !== 'string' ){
  	ll('ERROR: no proper golr url string argument');
      }
      if(	! golr_conf_obj._is_a || golr_conf_obj._is_a !== 'golr-conf.conf' ){
  	    ll('ERROR: no proper golr-conf.conf object argument');
  	    throw new Error('boink! ' + bbop.what_is(golr_conf_obj) );
  	}
      
      // Whether or not to prevent ajax events from going.
      // This may not be usable, or applicable, to all backends.
      this._safety = false;
  
      // Our default target url.
      this._solr_url = golr_loc;
  
      // Settle in the configurations.
      // this._golr_conf = new bbop_golr.conf(golr_conf_var);
      this._golr_conf = golr_conf_obj;
  
      // The current data batches that we are storing.
      this._batch_urls = [];
      this._batch_accumulator_func = function(){};
      this._batch_final_func = function(){};
  
      // The current state stack.
      this._excursions = [];
  
      // The current class/personality that we're using. It may be none.
      this._current_class = null;
  
      // Our (default) query and the real deal.
      this.fundamental_query = '*:*'; // cannot be changed
      this.default_query = '*:*'; // changable
      this.query = this.default_query; // current
  
      // Our (default) fl and whatever we have now.
      //this.default_fl = '*%2Cscore';
      this.default_fl = '*,score';
      this.current_fl = this.default_fl;
  
      // We remember defaults in the case of rows and start since they
      // are the core to any paging mechanisms and may change often.
      //this.default_rows = 25;
      //this.default_rows = 100;
      this.default_rows = 10;
      this.default_start = 0;
      this.current_rows = this.default_rows;
      this.current_start = this.default_start;
  
      // There is a reason for this...TODO: later (25+)
      this.default_facet_limit = 25;
      this.current_facet_limit = 25;
      // {facet_field_name: value, ...}
      this.current_facet_field_limits = {};
      // TODO: paging for facets;
      this.current_facet_offset = 25;
      this.current_facet_field_offsets = {};
  
      // Number of snippets to return when hl is enable
      this.default_hl_snippets = 1000;
  
      // Our default query args, with facet fields plugged in.
      this.query_variants =
  	{
  	    // Our default standard search type. This means we don't
  	    // have to explicitly add fields to the search (although
  	    // the query fields ('qf') are still necessary to make
  	    // anything real happen).
  	    defType: 'edismax',
  	    
  	    // Things unlikely to be touched.
  	    // There are unlikely to be messed with too much.
  	    qt: 'standard',
  	    indent: 'on',
  	    wt: 'json',
  	    //version: '2.2',
  	    rows: anchor.current_rows,
  	    start: anchor.current_start, // Solr is offset indexing
  	    //fl: '*%2Cscore',
  	    fl: anchor.default_fl,
      
  	    // Deprecated: see query_filters
  	    //fq: {},
  	    
  	    // Deprecated: see query_fields
  	    //qf: {},
  	    
  	    // Deprecated: see query
  	    //q: '*:*'
  
  	    // Control of facets.
  	    facet: 'true',
  	    'facet.mincount': 1,
  	    'facet.sort': 'count',
  	    'json.nl': 'arrarr', // only in facets right now
  	    'facet.limit': anchor.default_facet_limit
  	    // TODO?: 'f.???.facet.limit': 50,
  	    // TODO: 'json.nl': [flat|map|arrarr]
  
  	    // Deprecated: see facet_fields
  	    //'facet.field': []
  	};
  
      // This is the 'qf' parameter. Although we keep it, it only needs
      // to be exposed when the query ('q') field is set.
      //this.query_fields = [];
      this.query_fields = {};
  
      // A richer way to handle the 'fq' query variant.
      // It should look like:
      // {<filter>: {<value>:{'sticky_p':(t|f), 'negative_p':(t|f)}, ...}}
      this.query_filters = {};
  
      // The engine for the facet.field list.
      this.facet_fields = {};
  
      /*
       * Function: debug
       * 
       * Turn on or off the verbose messages. Uses <bbop.logger>, so
       * they should come out everywhere.
       * 
       * Parameters: 
       *  p - *[optional]* true or false for debugging
       *
       * Returns: 
       *  boolean; the current state of debugging
       */
      this.debug = function(p){
  	if( p === true || p === false ){
  	    this._logger.DEBUG = p;
  	    // TODO: add debug parameter a la include_highlighting
  	}
  	return this._logger.DEBUG;
      };
  
      /*
       * Function: minimal_query
       * 
       * The length of the minimal query to consider. Defaults to 3.
       * 
       * Parameters: 
       *  n - *[optional]* number, or nothing if just want current
       *
       * Returns: 
       *  number
       */
      this.minimal_query = function(n){
  	if( us.isNumber(n) ){
  	    anchor.minimal_query_length = n;
  	}
  	return this.minimal_query_length;
      };
  
      /*
       * Function: lite
       * 
       * Limit the returns fields (the parameter "fl") to the ones
       * defined in the set of fields defined in results, label fields
       * if available (i.e. "_label", "_map" when "_label" is
       * multi=valued), and "score" and "id".
       * 
       * The default is "false".
       * 
       * Parameters: 
       *  use_lite_p - *[optional]* true or false, none just returns current
       *
       * Returns: 
       *  boolean; the current state of lite-ness
       */
      this.lite = function(use_lite_p){
  
  	// Adjust the current state accordingly.
  	if( use_lite_p === true || use_lite_p === false ){
  	    if( use_lite_p === true ){
  		
  		// The actual collections and adjustment.
  		// First, this only works if we have a personality, so
  		// check to see if we have one.
  		var per = anchor.get_personality();
  		if( per ){
  		    // Since we have a personality, collect all of the
  		    // mentioned fields.
  		    var field_collection = {};
  		    var union = bbop.merge;
  		    var ccl = anchor._current_class;
  
  		    // Fill field_collection with the fields
  		    // in the given category.
  		    //loop(['boost', 'result', 'filter'],
  		    //loop(['result', 'filter'],
  		    each(['result'], function(cat){
  			field_collection = 
  			    union(field_collection, ccl.get_weights(cat));
  		    });
  		    
  		    // Next, flatten into a list.
  		    var flist = us.keys(field_collection);
  
  		    // Now for all the fields in these categories, see
  		    // if we can find additional "special" labels to
  		    // go with them.
  		    each(flist, function(flist_item){
  			//loop(['_label', '_label_searchable'],
  			each(['_label'], function(field_suffix){
  			    var new_field = flist_item + field_suffix;
  			    var nf_obj = ccl.get_field(new_field);
  			    if( nf_obj ){
  				flist.push(new_field);
  				
  				// There appears to be the
  				// thing label. If they are
  				// both multi-valued, then
  				// there will be a map as
  				// well.
  				if( nf_obj.is_multi() ){
  				    flist.push(flist_item + '_map');
  				}
  			    }
  			});
  		    });
  		    
  		    // Finally, set these fields (plus score) as the
  		    // new return fields.
  		    flist.push('score');
  		    flist.push('id');
  		    //anchor.current_fl = flist.join('%2C');
  		    anchor.current_fl = flist.join(',');
  		    anchor.set('fl', anchor.current_fl);
  		}
  		
  	    }else{ // else false
  		// Reset.
  		anchor.current_fl = anchor.default_fl;
  		anchor.set('fl', anchor.current_fl);
  	    }
  	}
  
  	// Return the current state.
  	var retval = false;
  	if( anchor.default_fl !== anchor.current_fl ){
  	    retval = true;
  	}
  	return retval;
      };
  
      // An internal helper function to munge the name of a field into
      // the name of its corresponding facet field.
      function _field_to_facet_field(field){
  	return 'f.' + field + '.facet.limit';
      }
      
      /*
       * Function: get_facet_limit
       * 
       * Get the limit for a specified facet or the global limit.
       * 
       * Parameters: 
       *  field - *[optional]* limit for a specific field; otherwise global value
       *
       * Returns: 
       *  integer or null
       */
      this.get_facet_limit = function(field){
  	var retval = null;
  
  	if( ! field ){
  	    retval = anchor.current_facet_limit;
  	}else{
  	    var f = _field_to_facet_field(field);
  	    var try_val = anchor.current_facet_field_limits[f];
  	    if( typeof(try_val) !== 'undefined' ){
  		retval = try_val;
  	    }
  	}
  
  	return retval;
      };
  
      /*
       * Function: set_facet_limit
       * 
       * Change the number of facet values returned per call.
       * The default is likely 25.
       * 
       * Just as in Solr, a -1 argument is how to indicate unlimted
       * facet returns.
       * 
       * This setting does not survive things like <resets_facet_limit>.
       * 
       * Parameters: 
       *  arg1 - (integer) set the global limit
       *
       * Parameters: 
       *  arg1 - (string) the name of the field to check
       *  arg2 - (integer) set the limit for this field
       *
       * Returns: 
       *  boolean on whether something was set
       */
      this.set_facet_limit = function(arg1, arg2){
  	var retval = false;
  
  	// Decide which form of the function we're using.
  	if( typeof(arg2) === 'undefined' &&
  	    bbop.what_is(arg1) === 'number' ){ // form one
  		
  		// Set
  		var nlimit = arg1;
  		anchor.current_facet_limit = nlimit;
  		anchor.set('facet.limit', anchor.current_facet_limit);
  		
  		retval = true;
  	
  	}else if( typeof(arg1) !== 'undefined' && 
  		  typeof(arg2) !== 'undefined' && 
  		  bbop.what_is(arg1) === 'string' &&
  		  bbop.what_is(arg2) === 'number' ){
  		      
  		      var field = _field_to_facet_field(arg1);
  		      var limit = arg2;
  		      anchor.current_facet_field_limits[field] = limit;
  		      
  		      retval = true;
  	}
  
  	return retval;
      };
  
      /*
       * Function: set_default_facet_limit
       * 
       * Permanently change the default number of facet values returned
       * per call. The default's default is likely 25.
       * 
       * Just as in Solr, a -1 argument is how to indicate unlimted
       * facet returns.
       * 
       * Parameters: 
       *  lim - (integer) set the global default limit
       *
       * Returns: 
       *  old default
       */
      this.set_default_facet_limit = function(lim){
  
  	// Capture ret.
  	var retval = anchor.default_facet_limit;
  
  	// Set
  	anchor.default_facet_limit = lim;
  	//anchor.set('facet.limit', anchor.default_facet_limit);
  		
  	return retval;
      };
  
      /*
       * Function: reset_facet_limit
       * 
       * Either reset the global limit to the original (likely 25)
       * and/or remove the specified filter. Sets everything back to the
       * original values or whatever was set by
       * <set_default_facet_limit>.
       * 
       * Parameters: 
       *  field - *[optional]* remove limit for a field; otherwise all and global
       *
       * Returns: 
       *  boolean on whether something was reset
       */
      this.reset_facet_limit = function(field){
  	var retval = false;
  
  	if( typeof(field) === 'undefined' ){
  	    // Eliminate all fields by blowing them away.
  	    anchor.current_facet_limit = anchor.default_facet_limit;
  	    anchor.set('facet.limit', anchor.current_facet_limit);
  	    anchor.current_facet_field_limits = {};
  	    retval = true;
  	}else{ // eliminate just the one field
  	    var f = _field_to_facet_field(field);
  	    if( typeof(anchor.current_facet_field_limits[f]) !== 'undefined' ){
  		delete anchor.current_facet_field_limits[f];
  		retval = true;
  	    }
  	}
  
  	return retval;
      };
  
      /*
       * Function: get_results_count
       * 
       * Get the current number of results that will be returned.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns: 
       *  integer
       */
      this.get_results_count = function(field){
  	return anchor.get('rows');
      };
  
      /*
       * Function: set_results_count
       * 
       * Change the number of result documents returned per call.
       * The default is likely 10.
       * 
       * Parameters: 
       *  count - (integer) set the global results count
       *
       * Returns:
       *  the count set
       */
      this.set_results_count = function(count){
  	anchor.set('rows', count);
  	anchor.current_rows = count;
  	return anchor.current_rows;
      };
  
      /*
       * Function: reset_results_count
       * 
       * Reset the number of documents to their original setting, likely
       * 10.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the new count
       */
      this.reset_results_count = function(){
  	anchor.set('rows', anchor.default_rows);
  	anchor.current_rows = anchor.default_rows;
  	return anchor.current_rows;
      };
  
      /*
       * Function: plist_to_property_hash
       *
       * Turn a plist to a hash containing the different properties that
       * can be defined for a query filter. Possible values are: '+'
       * (positive filter), '-' (negative filter), '*' (sticky filter),
       * '$' (transient). If mutually exclusive properties are defined
       * (e.g. both '+' and '-'), the last one will be used. Or, since
       * that is a call to silliness, let's say the behavior is
       * undefined.
       *
       * Parameters: 
       *  plist - *[optional]* a list of properties to apply to the filter
       *
       * Returns: 
       *  A hash version of the plist; otherwise, the default property hash
       */
      this.plist_to_property_hash = function(plist){
  
  	// Let's start with the default values.
  	var phash = {
  	    //'positive_p': true,
  	    'negative_p': false,
  	    //'transient_p': true
  	    'sticky_p': false
  	};
  
  	// If not defined, just return the default list.
  	if( plist ){	    
  	    each(plist, function(item){
  		if( item === '+' ){
  		    phash['negative_p'] = false;
  		    //phash['positive_p'] = true;
  		}else if( item === '-' ){
  		    phash['negative_p'] = true;
  		    //phash['positive_p'] = false;
  		}else if( item === '*' ){
  		    phash['sticky_p'] = true;
  		    //phash['transient_p'] = false;
  		}else if( item === '$' ){
  		    phash['sticky_p'] = false;
  		    //phash['transient_p'] = true;
  		}
  	    });
  	}
  
  	return phash;
      };
  
      /*
       * Function: add_query_filter_as_string
       *
       * Setter for query filters ('fq'). Acts as a 
       *
       * Parameters: 
       *  filter_string - filter (type) string (e.g. "-type:gene")
       *  plist - *[optional]* list of properties of the filter
       *
       * Returns: 
       *  (TODO) The current query filter hash.
       * 
       * See also:
       *  <add_query_filter>
       */
      this.add_query_filter_as_string = function(filter_string, plist){
  	
  	// Split the incoming filter string into its component parts.
  	var f_v = bbop.first_split(':', filter_string);
  	var fname = f_v[0];
  	var fval = f_v[1];
  
  	// Need to shuck the value from the quotes, as in load_url.
  	fval = bbop.dequote(fval);
  
  	var props = null;
  	if( us.isArray(plist) ){
  	    props = plist;
  	}else{
  	    props = [];
  	}
  
  	// Only continue on sensible inputs.
  	var ret = {};
  	if( fname !== '' && fval !== '' ){
  
  	    // Similar to the URL loader.
  	    var lead_char = fname.charAt(0);
  	    if( lead_char === '-' || lead_char === '+' ){
  		props.push(lead_char);
  		fname = fname.substr(1, fname.length -1);
  	    }
  	    
  	    ret = this.add_query_filter(fname, fval, props);
  	}
  
  	return ret;
      };
  
      /*
       * Function: add_query_filter
       *
       * Setter for query filters ('fq').
       *
       * Parameters: 
       *  filter - filter (type) string
       *  value - filter value string (or TODO: defined logic hash)
       *  plist - *[optional]* list of properties of the filter
       *
       * Returns: 
       *  (TODO) The current query filter hash.
       * 
       * See also:
       *  <plist_to_property_hash>
       */
      this.add_query_filter = function(filter, value, plist){
  	
  	// Make sure we've defined the group.
  	if( typeof(this.query_filters[filter]) === 'undefined' ){
  	    this.query_filters[filter] = {};
  	}
  
  	this.query_filters[filter][value] = this.plist_to_property_hash(plist);
  	
  	//ll("Current state: " + bbop.dump(this.query_filters));
  
  	return {}; // TODO
      };
  
      /*
       * Function: remove_query_filter
       *
       * Remover for query filters ('fq'), is a plist is specified, it
       * will only remove if all of the listed criteria are met.
       *
       * Parameters: 
       *  filter - filter (type) string
       *  value - filter value string (TODO: or defined logic hash)
       *  plist - *[optional]* list of properties of the filter
       *
       * Returns: 
       *  boolean (on success)
       */
      this.remove_query_filter = function(filter, value, plist){
  
  	// Default return value.
  	var retval = false;
  
  	// Internal helper to delete a low level key, and then if the
  	// top-level is empty, get that one too.
  	function _full_delete(hash, key1, key2){
  	    if( key1 && key2 && hash &&
  		hash[key1] && hash[key1][key2] ){
  		    delete hash[key1][key2];
  		}
  	    if( us.isEmpty(hash[key1]) ){
  		delete hash[key1];
  	    }
  	}
  
  	// If we have a filter, a value, and it's there...
  	if( filter && value &&
  	    anchor.query_filters[filter] &&
  	    anchor.query_filters[filter][value] ){
  
  		// If no real plist hash been defined, just go ahead
  		// and get rid of that. Otherwise, make sure that the
  		// defined plist and the stored properties are the
  		// same before deleting.
  		if( ! plist || us.isEmpty(plist) ){
  		    _full_delete(anchor.query_filters, filter, value);
  		    retval = true;
  		}else{
  		    
  		    var filter_phash = anchor.query_filters[filter][value];
  		    var in_phash = anchor.plist_to_property_hash(plist);
  		    
  		    if( bbop.is_same(filter_phash, in_phash) ){		
  			_full_delete(anchor.query_filters, filter, value);
  			retval = true;
  		    }
  		}
  	    }
  
  	return retval;
      };
  
      /*
       * Function: reset_query_filters
       *
       * Reset the query filters ('fq'); but leave sticky filters alone.
       *
       * Parameters: 
       *  n/a
       * 
       * Returns: 
       *  (TODO) The current query filter hash.
       */
      this.reset_query_filters = function(){
  
  	// Drill down and delete all non-stickies.
  	each(anchor.query_filters, function(values, filter){
  	    //ll('filter: ' + filter);
  	    each(values, function(props, value){
  		//ll('  value: ' + value);
  		var sticky_p = props['sticky_p'];
  		if( ! sticky_p ){
  		    //ll('hit: ' + filter + ', ' + value);
  		    anchor.remove_query_filter(filter, value);
  		}
  	    });
  	});
  	
  	return {}; // TODO
      };
  
      /*
       * Function: get_query_filter_properties
       *
       * Get a hash representing a query filter ('fq').
       *
       * Parameters: 
       *  key - filter string (TODO: or defined logic hash)
       *
       * Returns: 
       *  The current query filter hash for key.
       */
      this.get_query_filter_properties = function(filter, value){
  
  	// Default return value.
  	var retobj = null;
  	
  	// If we have a key and it's there...
  	var aqf = anchor.query_filters;
  	if( filter && value && aqf[filter] && aqf[filter][value] ){
  	    retobj =
  		{
  		    'filter' : filter,
  		    'value' : value,
  		    //'polarity': aqf[filter][value]['negative_p'],
  		    'negative_p': aqf[filter][value]['negative_p'],
  		    'sticky_p': aqf[filter][value]['sticky_p']
  		};
  	}
  
  	return retobj;
      };
  
      /*
       * Function: get_query_filters
       *
       * Get a list of hashes representing the query filters ('fq'). The
       * return lists look like:
       *
       * : [{'filter': A, 'value': B, 'negative_p': C, 'sticky_p': D}, ...]
       *
       * Where A and B are strings and C and D are booleans.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns: 
       *  A list of the current query filter hashs.
       */
      this.get_query_filters = function(){
  
  	var retlist = [];	
  	each(anchor.query_filters, function(values, f){
  	    each(values, function(props, v){
  		retlist.push(anchor.get_query_filter_properties(f, v));
  	    });
  	});
  
  	return retlist;
      };
  
      /*
       * Function: get_sticky_query_filters
       *
       * Get a list of hashes representing the current stucky query
       * filters ('fq'). See <get_query_filters> for a specification of
       * what the return type looks like.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns: 
       *  A list of the current sticky query filter hashs.
       * 
       * See also:
       *  <get_query_filters>
       */
      this.get_sticky_query_filters = function(){
  
  	var retlist = [];	
  	each(anchor.query_filters, function(values, f){
  	    each(values, function(props, v){
  		var qfp = anchor.get_query_filter_properties(f, v);
  		if( qfp['sticky_p'] === true ){
  		    retlist.push(qfp);			      
  		}
  	    });
  	});
  
  	return retlist;
      };
  
      // A little extra thing that we might need sometimes.
      this.query_extra = null;
  
      // Spaces can cause problems in URLs in some environments.
      //final_qurl = final_qurl.replace(/ /g, '%20');
      // Convert the URL into something more usable.
      // Because we internally use %09 as a special case, make sure
      // we don't double-up on it.
      this._query_encode = function(str_to_encode){
  
  	var fs1 = encodeURI(str_to_encode);
  	var fs2 = fs1.replace(/\%2509/g, '%09');
  
  	var final_encoding = fs2;
  	return final_encoding;
      };
  
      /*
       * Function: filter_list_to_assemble_hash
       *
       * Get all of our query filter variables and try and make
       * something of them that <get_assemble> can understand.
       *
       * Sticky doesn't matter here, but negativity does. However, we
       * can be pretty naive since the hashing should have already taken
       * out mutually exclusive dupes.
       * 
       * The argument is a list of query filter properties, as returned
       * by <get_query_filters> and <get_sticky_query_filters>.
       *
       * Parameters:
       *  flist - a list of query filter properties (see above)
       *
       * Returns:
       *  hash of filter names to value lists
       * 
       * See also:
       *  <get_query_filters>
       *  <get_sticky_query_filters>
       */
      this.filter_list_to_assemble_hash = function(flist){
  	var h = {};
  	each(flist, function(filter_property){
  	    
  	    // Grab only the properties that affect the
  	    // URL.
  	    var filter = filter_property['filter'];
  	    var value = filter_property['value'];
  	    var negative_p = filter_property['negative_p'];
  	    
  	    // We need to alter at the filter level.
  	    if( negative_p ){
  		filter = '-' + filter;
  	    }
  	    
  	    // Make sure it is defined.
  	    if( typeof(h[filter]) === 'undefined' ){
  		h[filter] = [];
  	    }
  	    h[filter].push(value);
  	});
  	return h;
      };
      
      /*
       * Function: sensible_query_p
       * 
       * Simply ask the manager if a free text query ('q') makes sense
       * at this point.
       * 
       * This currently means that the query text ('q') is one of:
       *  1) the same as the default query
       *  2) the same as the fundamental query
       *  3) three (3) (or whatever minimal_query is set to) characters long
       *  4) the empty string ('')
       * and that query fields ('qf') are defined.
       * 
       * This is an overridable opinion of the manager.
       * 
       * Parameters:
       *  n/a
       *
       * Returns:
       *  boolean
       */
      this.sensible_query_p = function(){
  	var retval = false;
  	var q = anchor.get_query();
  	var qf = anchor.query_field_set();
  
  	//console.log('q', q);
  	//console.log('qf', qf);
  
  	if( qf && ! us.isEmpty(qf) ){ // first hurdle
  
  	    if( q === anchor.get_default_query() ){
  		retval = true;
  	    }else if( q === anchor.get_fundamental_query() ){
  		retval = true;
  	    }else if( q && q.length >= anchor.minimal_query_length ){
  		retval = true;
  	    }else if( q === ''){
  		retval = true;
  	    }
  	}
  	return retval;
      };
  
      /*
       * Function: last_packet_sent
       *
       * It is up to the UI to do something interesting with this number.
       * 
       * Also remember that this number only rises through calls to
       * <update> or one of its wrappers. Calls to <get_query_url> and
       * the like will not affect this number.
       * 
       * Parameters:
       *  n/a 
       *
       * Returns:
       *  integer
       * 
       * See also:
       *  <update>
       */
      this.last_packet_sent = function(){
      	return anchor.last_sent_packet;
      };
  
      /*
       * Function: clear
       *
       * Clear all non-sticky query parameters to get back to a more
       * "original" state.
       * 
       * Not to be confused with <reset>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  n/a
       */
      this.clear = function(){
  
  	// Reset 'q'.
  	anchor.query = anchor.default_query;
  
  	// Reset 'fq', all but sticky.
  	anchor.reset_query_filters();
      };
  
      /*
       * Function: reset
       *
       * Manually trigger the "reset" chain of events.
       *
       * This is a curried wrapper for <update> and should be preferred
       * over a direct call to update.
       *
       * Note to be confused with <clear>.
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <update>
       */
      this.reset = function(){
  	return anchor.update('reset');
      };
  
      /*
       * Function: search
       *
       * Trigger the "search" chain of events.
       * Takes a field-keyed hash of bbop.logics as an argument.
       * 
       * This is a curried wrapper for <update> and should be preferred
       * over a direct call to update.
       * 
       * Parameters:
       *  n/a
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <update>
       */
      this.search = function(){
  	return anchor.update('search');
      };
  
      /*
       * Function: page
       *
       * Re-trigger the "search" chain of events, but with the variables
       * set for a different section of the results.
       * 
       * Note that this operates independently of any impossibilites in
       * the results--just how such paging would look and
       * triggering. Ths UI should handle impossibilities and the like.
       * 
       * This is a wrapper for <update> and should be preferred over a
       * direct call to update.
       * 
       * Parameters: 
       *  rows - the number of rows to return
       *  start - the offset of the rows to return
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <update>
       */
      this.page = function(rows, start){
  	anchor.set('rows', rows);
  	anchor.set('start', start);
  	return anchor.update('search', rows, start);
      };
  
      /*
       * Function: page_first
       *
       * Currently a convenience alias for <search>. Think about it--it
       * makes sense.
       * 
       * This is a wrapper for <page> and should be preferred over a
       * direct call to page.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  n/a
       * 
       * See also:
       *  <page>
       */
      this.page_first = anchor.search;
      
      /*
       * Function: page_previous
       * 
       * This is a wrapper for <page> and should be preferred over a
       * direct call to page.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <page>
       */
      this.page_previous = function(){
  	var do_rows = anchor.get_page_rows();
  	var do_offset = anchor.get_page_start() - do_rows;
  	return anchor.page(do_rows, do_offset);
      };
      
      /*
       * Function: page_next
       * 
       * This is a wrapper for <page> and should be preferred over a
       * direct call to page.
       * 
       * Parameters: 
       *  the query url (with the jQuery callback specific parameters)
       *
       * Returns:
       *  n/a
       * 
       * See also:
       *  <page>
       */
      this.page_next = function(){
  	var do_rows = anchor.get_page_rows();
  	var do_offset = anchor.get_page_start() + do_rows;
  	return anchor.page(do_rows, do_offset);
      };
      
      /*
       * Function: page_last
       * 
       * Trigger search on last page parameters.
       * 
       * Since the manager has no idea about what is actually being
       * returned, the real world number of total documents needs to be
       * added as an argument.
       * 
       * This is a wrapper for <page> and should be preferred over a
       * direct call to page.
       * 
       * Parameters: 
       *  total_document_count - integer for the total number of docs found
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <page>
       */
      this.page_last = function(total_document_count){
  	var do_rows = anchor.get_page_rows();
  	var mod = total_document_count % do_rows;
  	var do_offset = total_document_count - mod;
  	// ll("page_last: " + total_document_count + " " +
  	//    do_rows + " " + mod + " " + do_offset);
  	var ret = null;
  	if( mod === 0 ){
  	    ret = anchor.page(do_rows, do_offset - do_rows);
  	}else{
  	    ret = anchor.page(do_rows, do_offset);
  	}
  	return ret;
      };
  
      /*
       * Function: get_page_rows
       *
       * Return the number of rows the manager is currently set
       * to. Useful as an argument to <page>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  integer; the number of rows the manager is currently set to
       * 
       * See also:
       *  <page>
       */
      this.get_page_rows = function(){
  	return anchor.get('rows');
      };
  
      /*
       * Function: get_page_start
       *
       * Return the rows offset the manager is currently set to. Useful
       * as an argument to <page>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  integer; the offset the manager is currently set to
       * 
       * See also:
       *  <page>
       */
      this.get_page_start = function(){
  	return anchor.get('start');
      };
  
      /*
       * Function: add_query_field
       * 
       * Add a new query field to the query. 
       * 
       * This does not go through and expand into searchable fields, for
       * that see: <query_field_set>.
       *
       * Parameters: 
       *  qf - the query field to add
       *  boost - *[optional]* defaults to 1.0
       *
       * Returns:
       *  true or false on whether or not it is a new field
       * 
       * See also:
       *  <query_field_set>
       */
      this.add_query_field = function(qf, boost){
  	
  	var retval = false;
  
  	// Make sure that some boost is there.
  	if( typeof(boost) === 'undefined' ){
  	    boost = 1.0;
  	}
  
  	// Check.
  	if( typeof(anchor.query_fields[qf]) === 'undefined' ){
  	    retval = true;
  	}
  
  	// Add.
  	anchor.query_fields[qf] = boost;
  
  	return retval;
      };
  
      /*
       * Function: query_field_set
       *
       * Bulk getter/setter for the query fields--the fields that are
       * searched (and by what weight) when using a query ('q' or
       * set_query(), i.e. the 'qf' field).
       * 
       * This will always use searchable fields if possible,
       * automatically replacing the non-searchable versions (I can't
       * think of any reason to use non-searchable versions unless you
       * want your searches to not work) if a personality is set. If no
       * personality is set, it will just use the arguments as-is.
       * 
       * The argument replaces the current set.
       *
       * The qfs argument should be a hash like:
       * 
       *  {'field01': value01, ...}
       * 
       * Parameters: 
       *  qfs - *[optional]* query fields to set
       *
       * Returns:
       *  the current query_fields array (e.g. ["field01^value01", ...])
       */
      this.query_field_set = function(qfs){
  
  	// Covenience.
  	var cclass = anchor._current_class;
  
  	// Only do something if we have a query field set.
  	if( qfs ){
  	    
  	    // Only do the probing if a personality has been set.
  	    if( cclass ){
  
  		// Get the current searchable extension string from
  		// the personality class.
  		//var s_ext = cclass.searchable_extension();
  		// Actually, we're going to make this non-variable.
  		var s_ext = '_searchable';
  
  		// Probe the input to see if there are any searchable
  		// alternatives to try, use those instead.
  		var searchable_qfs = {};
  		each(qfs, function(value, filter){
  		    // If the probe fails, just put in
  		    // whatever is there.
  		    var cfield = cclass.get_field(filter);
  		    if( cfield && cfield.searchable() ){
  			//ll('filter/value:');
  			var new_f = filter + s_ext;
  			searchable_qfs[new_f] = value;
  		    }else{
  			searchable_qfs[filter] = value;
  		    }
  	    	});
  		qfs = searchable_qfs;
  	    }	    
  	    
  	    // Overwrite the current.
  	    anchor.query_fields = qfs;
  	}
  	
  	// Using the original information, convert them to the
  	// proper output format.
  	var output_format = [];
  	each(anchor.query_fields, function(value, filter){
  	    output_format.push(filter + '^' + value);
  	});
  	return output_format;
      };
  
      /*
       * Function: facets
       *
       * Bulk getter/setter for facets (technically 'facet.field').
       *
       * Parameters: 
       *  key - *[optional]* facet to add to the facet list
       *
       * Parameters: 
       *  list - *[optional]* list to replace the current list with
       *
       * Returns:
       *  the current facets hash.
       */
      this.facets = function(list_or_key){
  	if( list_or_key ){
  	    if( bbop.what_is(list_or_key) !== 'array' ){
  		// Arrayify it.
  		list_or_key = [list_or_key];
  	    }else{
  		// When there is a list, we are replacing the whole
  		// thing, so let's just poof it out of existance.
  		anchor.facet_fields = {};
  	    }
  	    each(list_or_key, function(item){
  		anchor.facet_fields[item] = true;
  	    });
  	}
  	return us.keys(anchor.facet_fields);
      };
  
      /*
       * Function: set_default_query
       *
       * Setter for the default query for the query variable ('q').
       * 
       * Call <reset_query> if you want to affect query immediately.
       * 
       * Parameters: 
       *  new_default_query - new default query string (or TODO: <bbop.logic>)
       *
       * Returns:
       *  the current setting of default query for ('q')
       */
      this.set_default_query = function(new_default_query){
  	anchor.default_query = new_default_query;
  	return anchor.default_query;
      };
  
      // /*
      //  * Function: set_first_run_query
      //  *
      //  * Setter for a first run query.  Normally, when <reset_query>, or
      //  * related method, is executed, we reset back to the default
      //  * query. This method sets a one time variable so a non empty
      //  * value can be used for the first reset.
      //  * 
      //  * Call <reset_query> if you want to affect query immediately.
      //  * 
      //  * Parameters: 
      //  *  first_run_query - query_string (or TODO: <bbop.logic>)
      //  *
      //  * Returns:
      //  *  the current setting of default query for ('q')
      //  */
      // this.set_first_run_query = function(first_run_query){
      // 	anchor.default_query = new_default_query;
      // 	return anchor.default_query;
      // };
  
      /*
       * Function: reset_default_query
       *
       * Reset the default query back to "*:*".
       * 
       * Call <reset_query> if you want to affect query immediately.
       * 
       * Parameters:
       *  n/a
       *
       * Returns:
       *  the current setting of default query ('q')
       */
      this.reset_default_query = function(){
  	anchor.default_query = anchor.fundamental_query;
  	return anchor.default_query;
      };
  
      /*
       * Function: set_query
       *
       * Setter for the query variable ('q').
       * 
       * Parameters: 
       *  new_query - new value for the query string (or TODO: <bbop.logic>)
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_comfy_query>
       */
      this.set_query = function(new_query){
  	anchor.query = new_query;
  	return anchor.query;
      };
  
      /*
       * Function: set_comfy_query
       *
       * A specialized setter for the query variable ('q'), as follows:
       *
       * If the input is all alphanum or space, the input is
       * tokenized. If there is one token, if it is at least three
       * characters, gets a wildcard '*'; if there are more tokens, the
       * last one gets a wild card.
       * 
       * This might be a more comfortable way to search for most naive
       * (non-power user) interfaces.
       * 
       * Parameters: 
       *  new_query - new value for the query string (or TODO: <bbop.logic>)
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_query>
       */
      this.set_comfy_query = function(new_query){
  
  	var comfy_query = new_query;
  
  	// Check that there is something there.
  	if( new_query && new_query.length && new_query.length > 0 ){
  
  	    // Check if the last real input has a space after it.
  	    var has_cursor_p = true;
  	    if( new_query.slice(-1) === ' ' ){
  		has_cursor_p = false;
  	    }
  
  	    // Now chomp it down again to get rid of whitespace.
  	    new_query = bbop.chomp(new_query);
  
  	    // Check (again) that there is something there.
  	    if( new_query && new_query.length && new_query.length > 0 ){
  
  		// That it is alphanum+space-ish and that we actually
  		// might want to add a wildcard (i.e. has cursor).
  		if( alphanum.test(new_query) && has_cursor_p ){
  	    
  		    // Break it into tokens and get the last.
  		    var tokens = new_query.split(new RegExp('\\s+'));
  		    var last_token = tokens[tokens.length -1];
  		    //ll('last: ' + last_token);
  		
  		    if( tokens.length === 1 ){
  			
  			// If it is three or more, add the wildcard.
  			if( last_token.length >= anchor.minimal_query_length ){
  			    tokens[tokens.length -1] = last_token + '*';
  			}
  		    }else{
  			tokens[tokens.length -1] = last_token + '*';
  		    }
  		    // And join it all back into our comfy query.
  		    comfy_query = tokens.join(' ');
  		}
  	    }
  	}
  
  	// Kick it back to the normal set_query.
  	return anchor.set_query(comfy_query);
      };
  
      /*
       * Function: set_id
       *
       * A limited setter, removing whatever else is on query. This is
       * for when you want to lock into one (unique) document by id
       * (essentially 'q=id:"foo"'). All other query operations behave
       * as they should around it.
       * 
       * Parameters: 
       *  new_id - string id
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_ids>
       */
      this.set_id = function(new_id){
  	anchor.query = 'id:' + bbop.ensure(new_id, '"');
  	return anchor.query;
      };
  
      // Function to unwind and lock a list if identifiers onto a field.
      function _lock_map(field, id_list){
  	var fixed_list = [];
  	each(id_list, function(item){
  	    fixed_list.push(bbop.ensure(item, '"'));
  	});
  	
  	var base_id_list = '(' + fixed_list.join(' OR ') + ')';
  
  	var ret_query = field + ':' + base_id_list;
  	return ret_query;
  	
      }
  
      /*
       * Function: set_ids
       *
       * Like <set_id>, a limited setter. It removes whatever else is on
       * query and replaces it with something like:
       * 
       * : gm.set_ids(['GO:1', 'GO:2'])
       * 
       * This is for when you want to lock into a set of documents by id. All
       * other query operations behave as they should around it.
       * 
       * Parameters: 
       *  id_list - a list of ids to search for
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_ids>
       */
      this.set_ids = function(id_list){
  	anchor.query = _lock_map('id', id_list);
  	return anchor.query;
      };
  
      /*
       * Function: set_targets
       *
       * Like a more generalized version of <set_ids>, a limited. It
       * removes whatever else is on query and replaces it with
       * something like:
       * 
       * : gm.set_targets(['GO:1', 'GO:2'], ['field_1', 'field_2'])
       * 
       * This is for when you want to lock into a set of documents by
       * locking onto identifiers in some set of search fields. All
       * other query operations behave as they should around it.
       * 
       * Parameters: 
       *  id_list - a list of ids to search for
       *  field_list - a list of fields ids to search across
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_ids>
       */
      this.set_targets = function(id_list, field_list){
  
  	var fixed_list = [];
  	each(field_list, function(field){
  	    fixed_list.push(_lock_map(field, id_list));
  	});
  
  	var sum = fixed_list.join(' OR ');
  
  	anchor.query = sum;
  	return anchor.query;
      };
  
      /*
       * Function: get_query
       *
       * Getter for the query variable ('q').
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of extra
       */
      this.get_query = function(){
  	return anchor.query;
      };
  
      /*
       * Function: get_default_query
       *
       * Getter for what the query variable 'q' will be set to on a
       * <reset_query>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of the default query
       */
      this.get_default_query = function(){
  	return anchor.default_query;
      };
  
      /*
       * Function: get_fundamental_query
       *
       * Getter for what the query variable 'q' will be set to on a
       * <reset_default_query>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of the fundamental default query
       */
      this.get_fundamental_query = function(){
  	return anchor.fundamental_query;
      };
  
      /*
       * Function: get_query
       *
       * Getter for the query variable ('q').
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of extra
       */
      this.get_query = function(){
  	return anchor.query;
      };
  
      /*
       * Function: reset_query
       *
       * Remove/reset the query variable ('q'); this set it back to the
       * default query.
       *
       * Parameters:
       *  none
       *
       * Returns:
       *  the current value of query
       * 
       * Also see:
       *  <set_default_query>
       *  <reset_default_query>
       */
      this.reset_query = function(){
  	anchor.query = anchor.default_query;
  	ll('reset query to default: ' + anchor.query);
  	return anchor.query;
      };
  
      /*
       * Function: set_extra
       *
       * Setter for the internal string variable to be appended to the
       * end of a query. For special use cases only (e.g. extend
       * functionality of the API safely).
       * 
       * Parameters: 
       *  new_extra - *[optional]* new value for the extras string
       *
       * Returns:
       *  the current setting of extra
       */
      this.set_extra = function(new_extra){
  	anchor.query_extra = new_extra;
  	return anchor.query_extra;
      };
  
      /*
       * Function: get_extra
       *
       * Getter for the internal string variable to be appended
       * to the end of a query.
       *
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of extra
       */
      this.get_extra = anchor.set_extra;
  
      /*
       * Function: remove_extra
       *
       * Remove/reset the extra bit.
       *
       * Parameters:
       *  none
       *
       * Returns:
       *  ""
       */
      this.remove_extra = function(){
  	anchor.query_extra = "";
  	return anchor.query_extra;
      };
  
      /*
       * Function: set
       *
       * Set an internal variable for the query. The internal variables
       * are typically things like 'qt', 'indent', etc.--things that you
       * might set and forget a while. It does /not/ include highly
       * dynamic variables (like callback and packet) or querying
       * variables like 'q' and 'fq'; for those you need to use the API.
       *
       * Parameters: 
       *  key - the name of the parameter to change
       *  new_val - what you want the new value to be
       *
       * Returns:
       *  n/a
       */
      this.set = function(key, new_val){
  	anchor.query_variants[key] = new_val;
      };
  
      /*
       * Function: get
       *
       * Get an internal variable for the query.
       *
       * See <set> for the kinds of parameters that can be read.
       * 
       * Parameters: 
       *  key - the name of the parameter to get
       *
       * Returns:
       *  The found value of the key.
       */
      this.get = function(key){
  	return anchor.query_variants[key];
      };
  
      /*
       * Function: unset
       *
       * Unset (remove) an internal variable for the query. Only usable on certain types of 
       * 
       * Only use is you really know what you're doing.
       *
       * Parameters: 
       *  key - the name of the parameter to unset/remove
       *
       * Returns:
       *  boolean; true false on whether the key was found
       */
      this.unset = function(key){
  	var retval = false;
  
  	if( typeof(anchor.query_variants[key]) !== 'undefined' ){
  	    retval = true;
  	    delete anchor.query_variants[key];
  	}
  
  	return retval;
      };
  
      /*
       * Function: include_highlighting
       *
       * Turn hilighting on or off (with true or false).
       * 
       * This essentially adds the parameters to the query string to
       * make sure that basic highlighting on the search is returned.
       * 
       * It starts off as false. The optional html_elt_str argument
       * defaults to:
       *  : <em class="hilite">
       *
       * Parameters: 
       *  hilite_p - *[optional]* boolean
       *  html_elt_str - *[serially optional]* the HTML element string to use
       *
       * Returns:
       *  either false or the current string being used for the return element
       */
      this.include_highlighting = function(hilite_p, html_elt_str){
  	var retval = false;
  
  	if( typeof(hilite_p) !== 'undefined' &&
  	    (hilite_p === true || hilite_p === false) ){
  	    if( hilite_p === true ){
  
  		// Set the default string if necessary.
  		if( ! html_elt_str ){ html_elt_str = '<em class="hilite">'; }
  
  		// Set the parameters.
  		anchor.set('hl', 'true');
  		anchor.set('hl.simple.pre', html_elt_str);
  
          anchor.set('hl.snippets', anchor.default_hl_snippets);
  
  		// And the retval is not longer false.
  		retval = html_elt_str;
  
  	    }else{
  		
  		// Unset the parameters.
  		anchor.unset('hl');
  		anchor.unset('hl.simple.pre');
  		anchor.unset('hl.snippets');
  	    }
  
  	}else{
  	    // Otherwise, just discover the current state and return
  	    // it.
  	    var cl_tmp = anchor.get('hl.simple.pre');
  	    if( typeof(cl_tmp) !== 'undefined' ){
  		retval = cl_tmp;
  	    }
  	}
  
  	return retval;
      };
  
      /*
       * Function: set_personality
       *
       * While we are always contacting the same Solr instance, we
       * sometimes want to have different weights, facets, etc. This
       * function allows us to use the pre-set ones defined in the
       * constructor configuration argument.
       * 
       * Currently, this only sets the 'facet.field' internal variable.
       *
       * Parameters: 
       *  personality_id - string
       *
       * Returns:
       *  Will return false if personality doesn't exist
       */
      this.set_personality = function(personality_id){
  	var retval = false;
  
  	// This sets the facet.field internal variable.
  	var cclass = anchor._golr_conf.get_class(personality_id);
  	if( cclass ){
  
  	    // Remember what our personality is.
  	    // WARNING: this line must go before the query_field_set
  	    // line below, or else we won't get the "smart" search.
  	    this._current_class = cclass;
  
  	    // Set the facets for our class.
  	    anchor.facets(cclass.field_order_by_weight('filter'));
  
  	    // Set the query field weights ('qf') necessary to make
  	    // queries run properly.
  	    anchor.query_field_set(cclass.get_weights('boost'));
  	    
  	    // Show that we did indeed set a personality.
  	    retval = true;
  	}
  
  	return retval;
      };
  
      /*
       * Function: get_personality
       *
       * Returns the current personality, null if none.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  Returns the current personality as a string, null if none is set
       */
      this.get_personality = function(){
  	var retval = null;
  
  	if( typeof(anchor._current_class) !== 'undefined' &&
  	    bbop.what_is(anchor._current_class) === 'golr-conf.conf_class'){
  	    retval = anchor._current_class.id();
  	}
  
  	return retval;
      };
  
      /*
       * Function: get_query_url
       *
       * Get the current invariant state of the manager returned as a
       * encoded URL string (using encodeURI()).
       * 
       * This means the URL for the current query to the GOlr store, but
       * without extra information about packets, callbacks, and the
       * like.
       * 
       * This is generally appropriate for getting data, but maybe not
       * for things like high-speed autocomplete where races can
       * occur. For those, you might want to consider <update> or
       * <search>.
       *
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  URL string
       * 
       * Also see:
       *  <update>, <search>
       */
      this.get_query_url = function(){
  
  	// Structure of the necessary invariant parts.	
  	var qurl = anchor._solr_url + 'select?';
  
  	// Filters to assemble.
  	var assemf = anchor.get_query_filters();
  	var fq = anchor.filter_list_to_assemble_hash(assemf);
  
  	// Add all of our different specialized hashes.
  	var things_to_add = [
  	    //bbop.get_assemble(anchor.query_invariants),
  	    //bbop.get_assemble(anchor.query_facets),
  	    bbop.get_assemble(anchor.query_variants),
  	    bbop.get_assemble(anchor.current_facet_field_limits),
  	    //bbop.get_assemble({'fq': anchor.query_sticky_filters}),
  	    bbop.get_assemble({'fq': fq}),
  	    bbop.get_assemble({'facet.field':
  			       us.keys(anchor.facet_fields)}),
  	    bbop.get_assemble({'q': anchor.query}),
  	    anchor.query_extra
  	];
  	// Add query_fields ('qf') iff query ('q') is set and it is
  	// not length 0.
  	if( anchor.query &&
  	    anchor.query.length &&
  	    anchor.query.length !== 0 &&
  	    anchor.query !== anchor.fundamental_query ){
  		var in_qf =
  		    bbop.get_assemble({'qf': anchor.query_field_set()});
  		things_to_add.push(in_qf);
  	    }
  	
  	// Assemble the assemblies into a single URL, throw out
  	// everything that seems like it isn't real to keep the URL as
  	// clean a possible.
  	var filtered_things =
  		bbop.pare(things_to_add, function(item, index){
  		    var retval = true;
  		    if( item && item !== '' ){
  			retval = false;
  		    }
  		    return retval;
  		});
  
  	var final_qurl = qurl + filtered_things.join('&');
  	final_qurl = anchor._query_encode(final_qurl);
  	ll('qurl: ' + final_qurl);
      	return final_qurl;
      };
  
      /*
       * Function: push_excursion
       *
       * Save the current state of the manager--data and sticky filter
       * information--onto an internal stack. Batch information is not
       * stored.
       * 
       * Useful for gettinginto a state, doing something else, then
       * returning to the original state.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  the number of items on the excursion stack
       * 
       * Also see:
       *  <get_query_url>
       *  <pop_excursion>
       */
      this.push_excursion = function(){
  	
  	var now = {
  	    // Save current state (data).
  	    data_url: anchor.get_query_url(),
  	    // Save current state (session).
  	    session: {
  		// Get the sticky filters.
  		sticky_filters: anchor.get_sticky_query_filters()
  	    }
  	};
  
  	// Save.
  	anchor._excursions.push(now);
  
  	// ...
      	return anchor._excursions.length;
      };
  
      /*
       * Function: pop_excursion
       *
       * Return to a previously pushed state. Batch items are not
       * recovered.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  boolean on whether a state was recovered
       * 
       * Also see:
       *  <get_query_url>
       *  <gpush_excursion>
       */
      this.pop_excursion = function(){
  	
  	var retval = false;
  
  	var then = anchor._excursions.pop();
  	if( then ){
  	    retval = true;
  
  	    // Recover data state.
  	    var then_data_url = then['data_url'];
  	    anchor.load_url(then_data_url);
  
  	    // Recover the session state.
  	    var then_session_stickies = then['session']['sticky_filters'];
  	    // Add the sticky filters.
  	    each(then_session_stickies, function(sticky){
  		var flt = sticky['filter'];
  		var fvl = sticky['value'];
  		var fpl = [];
  		if( sticky['negative_p'] === true ){
  		    fpl.push('-');
  		}
  		if( sticky['sticky_p'] === true ){
  		    fpl.push('*');
  		}
  		anchor.add_query_filter(flt, fvl, fpl);
  	    });	    
  	}
  	
      	return retval;
      };
  
      /*
       * Function: get_download_url
       *
       * Get the current invariant state of the manager returned as a
       * URL string.
       * 
       * This differs from <get_query_url> in that the generated string
       * is intended for text-processing uses rather than computerized
       * searching uses. The idea where is to create a TSV file for
       * downloading and consumption.
       * 
       * Instead of downloading all of the results, a limited listed set
       * can be downloaded using entity_list, which identifies documents by id.
       * 
       * The optional argument hash looks like:
       *  rows - the number of rows to return; defaults to: 1000
       *  encapsulator - how to enclose whitespace fields; defaults to: ""
       *  separator - separator between fields; defaults to: "%09" (tab)
       *  header - whether or not to show headers; defaults to: "false"
       *  mv_separator - separator for multi-valued fields; defaults to: "|"
       *  entity_list - list of specific download items in results; default null
       * 
       * With the entity list, keep in mind that null and an empty list
       * are handled in pretty much the same way--they are an indication
       * that we are going after nothing specific, and so all results
       * are game.
       * 
       * Parameters:
       *  field_list - a list of fields to return
       *  in_arg_hash - *[optional]* additional optional arguments
       * 
       * Returns:
       *  URL string
       * 
       * Also see:
       *  <get_query_url>
       */
      this.get_download_url = function(field_list, in_arg_hash){
  	
  	// Save current state.
  	anchor.push_excursion();
  
  	// Deal with getting arguments in properly.
  	var default_hash =
  	    {
  		rows : 1000,
  		encapsulator : '',
  		separator : "%09",
  		header : 'false',
  		mv_separator : "|",
  		entity_list : [],
  		golr_download_url : null
  	    };
  	var arg_hash = bbop.fold(default_hash, in_arg_hash);
  
  	// Make the changes we want.
  	anchor.set('wt', 'csv');
  	anchor.set('start', 0);
  	anchor.set('fl', field_list.join(','));
  	anchor.set('rows', arg_hash['rows']);
  	anchor.set('csv.encapsulator', arg_hash['encapsulator']);
  	anchor.set('csv.separator', arg_hash['separator']);
  	anchor.set('csv.header', arg_hash['header']);
  	anchor.set('csv.mv.separator', arg_hash['mv_separator']);
  
  	// A little more tricky, jimmy the entity list into the query
  	// if it's viable.
  	var entity_list = arg_hash['entity_list'];
  	if( typeof(entity_list) !== 'undefined' &&
  	    us.isArray(entity_list) &&
  	    entity_list.length > 0 ){
  		anchor.set_ids(entity_list);
  	}
  
  	// Get url.
  	var returl = anchor.get_query_url();
  
  	// If defined, switch download URL to something else.
  	if( arg_hash.golr_download_url ){
  	    returl = returl.replace(anchor._solr_url,
  				    arg_hash.golr_download_url);
  	}
  
  	// Reset the old state.
  	anchor.pop_excursion();
  
      	return returl;
      };
  
      /*
       * Function: get_filter_query_string
       *
       * Get the current state of the manager, as defined by the current
       * gross filter set--query, sticky filters, and standard filters--
       * returned as a URL query string (sans the '?').
       * 
       * This differs from <get_query_url> and <get_state_url> in that
       * the generated string is intended for applications that may want
       * just enough information to recover filter state when the
       * personality, and other types of information, are already
       * known. It is intended to be part of a light RESTy bookmarking
       * mechanism in larger application.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  query string for current filters (sans the '?')
       * 
       * Also see:
       *  <get_query_url>
       *  <get_state_url>
       */
      this.get_filter_query_string = function(){
  	
  	// // Save current state.
  	// anchor.push_excursion();
  
  	var q = anchor.get_query();
  
  	// Get the filters and sort them into sticky and "normal"
  	// sets.
  	var filters = anchor.get_query_filters();
  	var std_filters = [];
  	var sticky_filters = [];
  	each(filters, function(filter){
  	    if( filter['sticky_p'] ){
  		sticky_filters.push(filter);
  	    }else{
  		std_filters.push(filter);
  	    }
  	});
  	
  	var fq = anchor.filter_list_to_assemble_hash(std_filters);
  	var sfq = anchor.filter_list_to_assemble_hash(sticky_filters);
  
  	var things_to_add = [];
  	if( q ){
  	    things_to_add.push(bbop.get_assemble({'q': q}));
  	}
  	if( ! us.isEmpty(fq) ){
  	    things_to_add.push(bbop.get_assemble({'fq': fq}));
  	}
  	if( ! us.isEmpty(sfq) ){
  	    things_to_add.push(bbop.get_assemble({'sfq': sfq}));
  	}
  	    
  	// // Reset the old state.
  	// anchor.pop_excursion();
  
  	var final_qstr = things_to_add.join('&');
  	final_qstr = anchor._query_encode(final_qstr);
      	return final_qstr;
      };
  
      /*
       * Function: get_state_url
       *
       * Get the current invariant state of the manager, plus the
       * current personality as a parameter, returned as a URL string.
       * 
       * This differs from <get_query_url> in that the generated string
       * is intended for applications that may want a little more
       * information and hinting over just what the current search
       * is. This method essentially parameterizes some of the "hidden
       * state" of the manager.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  URL string
       * 
       * Also see:
       *  <get_query_url>
       */
      this.get_state_url = function(){
  	
  	// Save current state.
  	anchor.push_excursion();
  
  	// Make the changes we want. First, physically set the
  	// "personality", then set pins for jump-in recovery.
  	anchor.set('personality', anchor.get_personality());
  
  	// Explicitly set sticky pins for later recovery.
  	// Do this pretty much exactly like we do for get_query_url().
  	var sticky_filters = anchor.get_sticky_query_filters();
  	var sfq = anchor.filter_list_to_assemble_hash(sticky_filters);
  	anchor.set('sfq', sfq);
  	
  	// Get url.
  	var returl = anchor.get_query_url();
  
  	// Reset the old state.
  	anchor.pop_excursion();
  
      	return returl;
      };
  
      /*
       * Function: load_url
       *
       * Makes a a best attempt to recover the state of a manager from
       * the clues left in a data url. This can also (and probably
       * should) be thought of as a "load bookmark"
       * function. Theoretically, you should even be able to use
       * "bookmarks" from alien installations.
       * 
       * Note that while this recovers enough to get the same data,
       * certain "session"/"preference" type things that are not encoded
       * in the url (e.g. filter stickiness, the contents of batch
       * queues, non-default base queries, etc.) will not be replayed
       * and must be recovered or guessed on an app by app basis..
       * 
       * Warning: this currently only replays a small subset of possible
       * parameters. Currently: personality, q, fq, ???. In the future,
       * this should no all non-session information.
       * 
       * Warning: Because there is more to bookmarks than just the major
       * stuff, variants not supplied in the bookmark will be removed.
       * 
       * This returns true if the parameter portions of the new and
       * bookmark urls match. However, this is often not the case--think
       * shifting personalities, etc.
       * 
       * Parameters:
       *  url - A URL string generated by a manager's get_query_url (or similar)
       * 
       * Returns:
       *  boolean
       */
      this.load_url = function(url){
  
  	// // Some Regexps that would be nice to just compile once.
  	// var regexp_url_space = /\%20/g; // '%20' === ' '
  	// var regexp_url_quote = /\%22/g; // '%22' === '"'
  	// var regexp_url_left_paren = /\%28/g; // '%28' === '('
  	// var regexp_url_right_paren = /\%29/g; // '%29' === ')'
  
  	// We are assuming that we are consuming our own URLs from
  	// get_query_url(), so we start by attempting to decode it
  	// (TODO: need a tab watch here)?
  	var decoded_url = decodeURI(url);
  
  	// Break down url.
  	var in_params = bbop.url_parameters(decoded_url);
  
  	// First, look for the personality setting and invoke it if
  	// it's there--it will dominate unless we take care of it first.
  	// Also note the all the keys that we see (for later erasure
  	// of excess).
  	var seen_params = {};
  	each(in_params, function(ip){
  	    var key = ip[0];
  	    var val = ip[1];
  	    if( key === 'personality' && val && val !== '' ){
  		anchor.set_personality(val);
  	    }
  	    seen_params[key] = true;
  	});
  	
  	// Now cycle through the the parameters again and invoke the
  	// appropriate functions to bring them in line.
  	var sticky_cache = {};
  	each(in_params, function(ip){
  	    var key = ip[0];
  	    var val = ip[1];
  	    if( typeof(val) !== 'undefined' && val !== '' ){
  		if( key === 'personality' ){
  		    // Already did it, skip.
  		}else if( key === 'q' ){
  		    anchor.set_query(val);
  		}else if( key === 'fq' || key === 'sfq' ){
  		    // Split the fq (or sfq) parameter.
  		    var fnv = bbop.first_split(':', val);
  		    var fname = fnv[0];
  		    var fval = fnv[1];
  		    //ll('HERE: fname: ' + fname);
  		    //ll('HERE: fval: ' + fval);
  		    if( fname && fval ){
  			
  			var plist = [];
  			
  			// Remove leading sign on a filter and
  			// add it to the plist.
  			var lead_char = fname.charAt(0);
  			if( lead_char === '-' || lead_char === '+' ){
  			    plist.push(lead_char);
  			    fname = fname.substr(1, fname.length -1);
  			}
  			
  			// // TODO: 
  			// // If the fval looks like it has not been
  			// // decoded (like from a URL-safe
  			// // bookmark), go ahead and do so.
  			// fval = fval.replace(regexp_url_space, ' ');
  			// fval = fval.replace(regexp_url_quote, '"');
  			// fval = fval.replace(regexp_url_left_paren, '(');
  			// fval = fval.replace(regexp_url_right_paren,')');
  			
  			// Do not allow quotes in--they will be
  			// added by the assembler.
  			fval = bbop.dequote(fval);
  			
  			// Make it sticky it it came in on "sfq".
  			// Note if this is the sticky form.
  			var skey = fname + '^' + fval;
  			if( key === 'sfq' ){
  			    sticky_cache[skey] = true;
  			    plist.push('*');
  			}
  			
  			// Add the query filter properly, but
  			// only if we have not already added the
  			// sticky form (prevent clobbering).
  			if( ! bbop.is_defined(sticky_cache[skey]) ||
  			    key === 'sfq'){
  			    anchor.add_query_filter(fname, fval, plist);
  			    
  			}
  		    }
  		}else if( key === 'qf' ){
  		    // qf is handles a little strangely...
  		    var foo = bbop.first_split('^', val);
  		    //ll('qf: key: '+ key +', val: '+ val +', foo: '+ foo);
  		    anchor.add_query_field(foo[0], foo[1]);
  		}else if( key === 'facet.field' ){
  		    anchor.facets(val);
  		}else if( key === 'start' || key === 'rows' ){
  		    // Numbers need to be handled carefully.
  		    if( bbop.what_is(val) === 'string' ){
  			val = parseFloat(val);
  		    }
  		    anchor.set(key, val);
  		}else{
  		    // This one catches all of the non-special
  		    // parameters and resets them using .set().
  		    anchor.set(key, val);
  		    // if( key === 'fq' ){
  		    //     throw new Error("OI");			     
  		    // }
  		}
  	    }
  	});
  	
  	// Now go through and remove all of the query variant
  	// parameters that were not seen in the bookmark.
  	each(anchor.query_variants, function(val, key){
  	    if( typeof(seen_params[key]) === 'undefined'){
  		anchor.unset(key);
  	    }
  	});
  	
  	// Produce our own url from what we've done. If the parameters
  	// match with the incoming argument's return true.
  	var curr_url = anchor.get_query_url();
  	var curr_params = bbop.url_parameters(curr_url);
  	var differences = 0;
  	if( in_params.length === curr_params.length ){
  	    each(in_params, function(in_p, i){
  		var curr_p = curr_params[i];
  		if( in_p.length === curr_p.length ){
  		    if( in_p.length === 1 ){
  			if( in_p[0] === curr_p[0] ){
  			    // match!
  			}else{
  			    differences++;
  			}
  		    }else if( in_p.length === 2 ){
  			if( in_p[0] === curr_p[0] && in_p[1] === curr_p[1] ){
  			    // match!
  			}else{
  			    differences++;
  			}
  		    }
  		}else{
  		    differences++;
  		}
  	    });
  	}else{
  	    differences++;
  	}
  	
  	// Tally the differences and decides if they're the same.
  	var retval = false;
  	if( differences === 0 ){
  	    retval = true;
  	}
      	return retval;
      };
  
      /*
       * Function: add_to_batch
       *
       * "Save" the current manager state to run later in serial batch
       * mode.
       * 
       * The actual job of running these batches is left to the
       * implementation of the sub-managers; probably in "run_batch".
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  state url
       */
      this.add_to_batch = function(){
  	var qurl = anchor.get_query_url();
  	anchor._batch_urls.push(qurl);
      	return qurl;
      };
  
      /*
       * Function: batch_urls
       *
       * Return a pointer to the current batch urls.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  array
       */
      this.batch_urls = function(){
      	return anchor._batch_urls;
      };
  
      /*
       * Function: next_batch_url
       *
       * Return the next data to be processed, removing it from the
       * batch queue in the process.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  state url or null
       */
      this.next_batch_url = function(){
      	return anchor._batch_urls.shift() || null;
      };
  
      /*
       * Function: reset_batch
       *
       * Clear the currently queued data batch.
       * 
       * The actual job of running these batches is left to the
       * implementation of the sub-managers; probably in "run_batch".
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  the number of items cleared
       */
      this.reset_batch = function(){
  	var num = anchor._batch_urls.length;
  	anchor._batch_urls = [];
      	return num;
      };
  }
func_code_string: function (golr_loc, golr_conf_obj, engine, mode){
      registry.call(this, ['prerun',
  			 'reset',
  			 'search',
  			 'error',
  			 'postrun']);
      this._is_a = 'bbop-manager-golr';
      var anchor = this; // get a good self-reference point
  
      // Per-manager logger.
      this._logger = new bbop.logger(this._is_a);
      //this._logger.DEBUG = true;
      this._logger.DEBUG = false;
      function ll(str){ anchor._logger.kvetch(str); }
  
      // Setup right handler subsystem--either returning a direct
      // response or a promise, depending.
      anchor._engine = engine || null;
      anchor._mode = mode || null;
      anchor._runner = function(resource, payload){
  	var ret = null;
  	// if( typeof(anchor._engine) === 'undefined' ){
  	//     throw new Error('"engine" not set in new bbop-manager-golr');
  	// }
  	if( anchor._mode === 'sync' ){
  	    ret = anchor._engine.fetch(resource, payload);
  	}else if( anchor._mode === 'async' ){
  	    ret = anchor._engine.start(resource, payload);
  	}else{
  	    // throw new Error('"mode" not set in new bbop-manager-golr');
  	    return resource;
  	}
  	return ret;
      };
  
      // The callback function called after a successful AJAX
      // intialization/reset call. First it runs some template code,
      // then it does all of the callbacks.
      anchor._run_reset_callbacks = function(response){
  	ll('run reset callbacks...');
  	//var response = new golr_response(json_data);
  	anchor.apply_callbacks('reset', [response, anchor]);
  	anchor.apply_callbacks('postrun', [response, anchor]);
      };
  
      // The main callback function called after a successful AJAX call in
      // the update function.
      anchor._run_search_callbacks = function(response){
  	ll('run search callbacks...');
  	//var response = new golr_response(json_data);
  	anchor.apply_callbacks('search', [response, anchor]);
  	anchor.apply_callbacks('postrun', [response, anchor]);
      };
  
      // This set is called when we run into a problem.
      anchor._run_error_callbacks = function(response){
  	ll('run error callbacks...');
  	//var response = new golr_response(json_data);
  	anchor.apply_callbacks('error', [response, anchor]);
  	anchor.apply_callbacks('postrun', [response, anchor]);
      };
  
      // The registries can only be applied if the engine is present.
      if( engine ){
  
  	// Re-contextualize run_promise_functions().
  	anchor.run_promise_functions = function(promise_function_stack, 
  						accumulator_function,
  						final_function,
  						error_function){
  	    // NOTE: Cannot sensibly use Function.call here as engine
  	    // is not really the superclass of this manager.
  	    return engine.run_promise_functions(promise_function_stack,
  						accumulator_function,
  						final_function,
  						error_function);
  	};
  
  	// Setup the appropriate callbacks in the engine for success.
  	anchor._engine.register('success', function(response){
  	    
      	    //console.log(anchor._engine);
      	    //console.log(response._raw);
  	    
              // 
              if( ! response.success() ){
  		throw new Error("Unsuccessful response from golr server!");
              }else{
  		var cb_type = response.callback_type();
  		//console.log('okay response from server, will probe type...: '+cb_type);
  		if( cb_type === 'reset' ){
                      anchor._run_reset_callbacks(response);
  		}else if( cb_type === 'search' ){
                      anchor._run_search_callbacks(response);
  		}else{
                      throw new Error("Unknown callback type (runner): "+cb_type);
  		}
              }
  	});
  	
  	// And, more easily, setup the appropriate callbacks in the
  	// engine for failure.
  	anchor._engine.register('error', function(response){
      	    anchor._run_error_callbacks(response);
  	});
  	
      }
  
      // Just want to compile these once.
      var alphanum = new RegExp(/^[a-zA-Z0-9 ]+$/);
  
      this.minimal_query_length = 3;
  
      // To help keep requests from the past haunting us. Actually doing
      // something with this number is up to the UI.
      this.last_sent_packet = 0;
      //this.last_received_packet = 0;
  
      // Lightly check incoming arguments.
      // There should be a string url argument.
      // There could be a hash of pinned filters argument.
      if( ! golr_loc || ! golr_conf_obj ){
  	ll('ERROR: no proper arguments');
      }
      if( typeof golr_loc !== 'string' ){
  	ll('ERROR: no proper golr url string argument');
      }
      if(	! golr_conf_obj._is_a || golr_conf_obj._is_a !== 'golr-conf.conf' ){
  	    ll('ERROR: no proper golr-conf.conf object argument');
  	    throw new Error('boink! ' + bbop.what_is(golr_conf_obj) );
  	}
      
      // Whether or not to prevent ajax events from going.
      // This may not be usable, or applicable, to all backends.
      this._safety = false;
  
      // Our default target url.
      this._solr_url = golr_loc;
  
      // Settle in the configurations.
      // this._golr_conf = new bbop_golr.conf(golr_conf_var);
      this._golr_conf = golr_conf_obj;
  
      // The current data batches that we are storing.
      this._batch_urls = [];
      this._batch_accumulator_func = function(){};
      this._batch_final_func = function(){};
  
      // The current state stack.
      this._excursions = [];
  
      // The current class/personality that we're using. It may be none.
      this._current_class = null;
  
      // Our (default) query and the real deal.
      this.fundamental_query = '*:*'; // cannot be changed
      this.default_query = '*:*'; // changable
      this.query = this.default_query; // current
  
      // Our (default) fl and whatever we have now.
      //this.default_fl = '*%2Cscore';
      this.default_fl = '*,score';
      this.current_fl = this.default_fl;
  
      // We remember defaults in the case of rows and start since they
      // are the core to any paging mechanisms and may change often.
      //this.default_rows = 25;
      //this.default_rows = 100;
      this.default_rows = 10;
      this.default_start = 0;
      this.current_rows = this.default_rows;
      this.current_start = this.default_start;
  
      // There is a reason for this...TODO: later (25+)
      this.default_facet_limit = 25;
      this.current_facet_limit = 25;
      // {facet_field_name: value, ...}
      this.current_facet_field_limits = {};
      // TODO: paging for facets;
      this.current_facet_offset = 25;
      this.current_facet_field_offsets = {};
  
      // Number of snippets to return when hl is enable
      this.default_hl_snippets = 1000;
  
      // Our default query args, with facet fields plugged in.
      this.query_variants =
  	{
  	    // Our default standard search type. This means we don't
  	    // have to explicitly add fields to the search (although
  	    // the query fields ('qf') are still necessary to make
  	    // anything real happen).
  	    defType: 'edismax',
  	    
  	    // Things unlikely to be touched.
  	    // There are unlikely to be messed with too much.
  	    qt: 'standard',
  	    indent: 'on',
  	    wt: 'json',
  	    //version: '2.2',
  	    rows: anchor.current_rows,
  	    start: anchor.current_start, // Solr is offset indexing
  	    //fl: '*%2Cscore',
  	    fl: anchor.default_fl,
      
  	    // Deprecated: see query_filters
  	    //fq: {},
  	    
  	    // Deprecated: see query_fields
  	    //qf: {},
  	    
  	    // Deprecated: see query
  	    //q: '*:*'
  
  	    // Control of facets.
  	    facet: 'true',
  	    'facet.mincount': 1,
  	    'facet.sort': 'count',
  	    'json.nl': 'arrarr', // only in facets right now
  	    'facet.limit': anchor.default_facet_limit
  	    // TODO?: 'f.???.facet.limit': 50,
  	    // TODO: 'json.nl': [flat|map|arrarr]
  
  	    // Deprecated: see facet_fields
  	    //'facet.field': []
  	};
  
      // This is the 'qf' parameter. Although we keep it, it only needs
      // to be exposed when the query ('q') field is set.
      //this.query_fields = [];
      this.query_fields = {};
  
      // A richer way to handle the 'fq' query variant.
      // It should look like:
      // {<filter>: {<value>:{'sticky_p':(t|f), 'negative_p':(t|f)}, ...}}
      this.query_filters = {};
  
      // The engine for the facet.field list.
      this.facet_fields = {};
  
      /*
       * Function: debug
       * 
       * Turn on or off the verbose messages. Uses <bbop.logger>, so
       * they should come out everywhere.
       * 
       * Parameters: 
       *  p - *[optional]* true or false for debugging
       *
       * Returns: 
       *  boolean; the current state of debugging
       */
      this.debug = function(p){
  	if( p === true || p === false ){
  	    this._logger.DEBUG = p;
  	    // TODO: add debug parameter a la include_highlighting
  	}
  	return this._logger.DEBUG;
      };
  
      /*
       * Function: minimal_query
       * 
       * The length of the minimal query to consider. Defaults to 3.
       * 
       * Parameters: 
       *  n - *[optional]* number, or nothing if just want current
       *
       * Returns: 
       *  number
       */
      this.minimal_query = function(n){
  	if( us.isNumber(n) ){
  	    anchor.minimal_query_length = n;
  	}
  	return this.minimal_query_length;
      };
  
      /*
       * Function: lite
       * 
       * Limit the returns fields (the parameter "fl") to the ones
       * defined in the set of fields defined in results, label fields
       * if available (i.e. "_label", "_map" when "_label" is
       * multi=valued), and "score" and "id".
       * 
       * The default is "false".
       * 
       * Parameters: 
       *  use_lite_p - *[optional]* true or false, none just returns current
       *
       * Returns: 
       *  boolean; the current state of lite-ness
       */
      this.lite = function(use_lite_p){
  
  	// Adjust the current state accordingly.
  	if( use_lite_p === true || use_lite_p === false ){
  	    if( use_lite_p === true ){
  		
  		// The actual collections and adjustment.
  		// First, this only works if we have a personality, so
  		// check to see if we have one.
  		var per = anchor.get_personality();
  		if( per ){
  		    // Since we have a personality, collect all of the
  		    // mentioned fields.
  		    var field_collection = {};
  		    var union = bbop.merge;
  		    var ccl = anchor._current_class;
  
  		    // Fill field_collection with the fields
  		    // in the given category.
  		    //loop(['boost', 'result', 'filter'],
  		    //loop(['result', 'filter'],
  		    each(['result'], function(cat){
  			field_collection = 
  			    union(field_collection, ccl.get_weights(cat));
  		    });
  		    
  		    // Next, flatten into a list.
  		    var flist = us.keys(field_collection);
  
  		    // Now for all the fields in these categories, see
  		    // if we can find additional "special" labels to
  		    // go with them.
  		    each(flist, function(flist_item){
  			//loop(['_label', '_label_searchable'],
  			each(['_label'], function(field_suffix){
  			    var new_field = flist_item + field_suffix;
  			    var nf_obj = ccl.get_field(new_field);
  			    if( nf_obj ){
  				flist.push(new_field);
  				
  				// There appears to be the
  				// thing label. If they are
  				// both multi-valued, then
  				// there will be a map as
  				// well.
  				if( nf_obj.is_multi() ){
  				    flist.push(flist_item + '_map');
  				}
  			    }
  			});
  		    });
  		    
  		    // Finally, set these fields (plus score) as the
  		    // new return fields.
  		    flist.push('score');
  		    flist.push('id');
  		    //anchor.current_fl = flist.join('%2C');
  		    anchor.current_fl = flist.join(',');
  		    anchor.set('fl', anchor.current_fl);
  		}
  		
  	    }else{ // else false
  		// Reset.
  		anchor.current_fl = anchor.default_fl;
  		anchor.set('fl', anchor.current_fl);
  	    }
  	}
  
  	// Return the current state.
  	var retval = false;
  	if( anchor.default_fl !== anchor.current_fl ){
  	    retval = true;
  	}
  	return retval;
      };
  
      // An internal helper function to munge the name of a field into
      // the name of its corresponding facet field.
      function _field_to_facet_field(field){
  	return 'f.' + field + '.facet.limit';
      }
      
      /*
       * Function: get_facet_limit
       * 
       * Get the limit for a specified facet or the global limit.
       * 
       * Parameters: 
       *  field - *[optional]* limit for a specific field; otherwise global value
       *
       * Returns: 
       *  integer or null
       */
      this.get_facet_limit = function(field){
  	var retval = null;
  
  	if( ! field ){
  	    retval = anchor.current_facet_limit;
  	}else{
  	    var f = _field_to_facet_field(field);
  	    var try_val = anchor.current_facet_field_limits[f];
  	    if( typeof(try_val) !== 'undefined' ){
  		retval = try_val;
  	    }
  	}
  
  	return retval;
      };
  
      /*
       * Function: set_facet_limit
       * 
       * Change the number of facet values returned per call.
       * The default is likely 25.
       * 
       * Just as in Solr, a -1 argument is how to indicate unlimted
       * facet returns.
       * 
       * This setting does not survive things like <resets_facet_limit>.
       * 
       * Parameters: 
       *  arg1 - (integer) set the global limit
       *
       * Parameters: 
       *  arg1 - (string) the name of the field to check
       *  arg2 - (integer) set the limit for this field
       *
       * Returns: 
       *  boolean on whether something was set
       */
      this.set_facet_limit = function(arg1, arg2){
  	var retval = false;
  
  	// Decide which form of the function we're using.
  	if( typeof(arg2) === 'undefined' &&
  	    bbop.what_is(arg1) === 'number' ){ // form one
  		
  		// Set
  		var nlimit = arg1;
  		anchor.current_facet_limit = nlimit;
  		anchor.set('facet.limit', anchor.current_facet_limit);
  		
  		retval = true;
  	
  	}else if( typeof(arg1) !== 'undefined' && 
  		  typeof(arg2) !== 'undefined' && 
  		  bbop.what_is(arg1) === 'string' &&
  		  bbop.what_is(arg2) === 'number' ){
  		      
  		      var field = _field_to_facet_field(arg1);
  		      var limit = arg2;
  		      anchor.current_facet_field_limits[field] = limit;
  		      
  		      retval = true;
  	}
  
  	return retval;
      };
  
      /*
       * Function: set_default_facet_limit
       * 
       * Permanently change the default number of facet values returned
       * per call. The default's default is likely 25.
       * 
       * Just as in Solr, a -1 argument is how to indicate unlimted
       * facet returns.
       * 
       * Parameters: 
       *  lim - (integer) set the global default limit
       *
       * Returns: 
       *  old default
       */
      this.set_default_facet_limit = function(lim){
  
  	// Capture ret.
  	var retval = anchor.default_facet_limit;
  
  	// Set
  	anchor.default_facet_limit = lim;
  	//anchor.set('facet.limit', anchor.default_facet_limit);
  		
  	return retval;
      };
  
      /*
       * Function: reset_facet_limit
       * 
       * Either reset the global limit to the original (likely 25)
       * and/or remove the specified filter. Sets everything back to the
       * original values or whatever was set by
       * <set_default_facet_limit>.
       * 
       * Parameters: 
       *  field - *[optional]* remove limit for a field; otherwise all and global
       *
       * Returns: 
       *  boolean on whether something was reset
       */
      this.reset_facet_limit = function(field){
  	var retval = false;
  
  	if( typeof(field) === 'undefined' ){
  	    // Eliminate all fields by blowing them away.
  	    anchor.current_facet_limit = anchor.default_facet_limit;
  	    anchor.set('facet.limit', anchor.current_facet_limit);
  	    anchor.current_facet_field_limits = {};
  	    retval = true;
  	}else{ // eliminate just the one field
  	    var f = _field_to_facet_field(field);
  	    if( typeof(anchor.current_facet_field_limits[f]) !== 'undefined' ){
  		delete anchor.current_facet_field_limits[f];
  		retval = true;
  	    }
  	}
  
  	return retval;
      };
  
      /*
       * Function: get_results_count
       * 
       * Get the current number of results that will be returned.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns: 
       *  integer
       */
      this.get_results_count = function(field){
  	return anchor.get('rows');
      };
  
      /*
       * Function: set_results_count
       * 
       * Change the number of result documents returned per call.
       * The default is likely 10.
       * 
       * Parameters: 
       *  count - (integer) set the global results count
       *
       * Returns:
       *  the count set
       */
      this.set_results_count = function(count){
  	anchor.set('rows', count);
  	anchor.current_rows = count;
  	return anchor.current_rows;
      };
  
      /*
       * Function: reset_results_count
       * 
       * Reset the number of documents to their original setting, likely
       * 10.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the new count
       */
      this.reset_results_count = function(){
  	anchor.set('rows', anchor.default_rows);
  	anchor.current_rows = anchor.default_rows;
  	return anchor.current_rows;
      };
  
      /*
       * Function: plist_to_property_hash
       *
       * Turn a plist to a hash containing the different properties that
       * can be defined for a query filter. Possible values are: '+'
       * (positive filter), '-' (negative filter), '*' (sticky filter),
       * '$' (transient). If mutually exclusive properties are defined
       * (e.g. both '+' and '-'), the last one will be used. Or, since
       * that is a call to silliness, let's say the behavior is
       * undefined.
       *
       * Parameters: 
       *  plist - *[optional]* a list of properties to apply to the filter
       *
       * Returns: 
       *  A hash version of the plist; otherwise, the default property hash
       */
      this.plist_to_property_hash = function(plist){
  
  	// Let's start with the default values.
  	var phash = {
  	    //'positive_p': true,
  	    'negative_p': false,
  	    //'transient_p': true
  	    'sticky_p': false
  	};
  
  	// If not defined, just return the default list.
  	if( plist ){	    
  	    each(plist, function(item){
  		if( item === '+' ){
  		    phash['negative_p'] = false;
  		    //phash['positive_p'] = true;
  		}else if( item === '-' ){
  		    phash['negative_p'] = true;
  		    //phash['positive_p'] = false;
  		}else if( item === '*' ){
  		    phash['sticky_p'] = true;
  		    //phash['transient_p'] = false;
  		}else if( item === '$' ){
  		    phash['sticky_p'] = false;
  		    //phash['transient_p'] = true;
  		}
  	    });
  	}
  
  	return phash;
      };
  
      /*
       * Function: add_query_filter_as_string
       *
       * Setter for query filters ('fq'). Acts as a 
       *
       * Parameters: 
       *  filter_string - filter (type) string (e.g. "-type:gene")
       *  plist - *[optional]* list of properties of the filter
       *
       * Returns: 
       *  (TODO) The current query filter hash.
       * 
       * See also:
       *  <add_query_filter>
       */
      this.add_query_filter_as_string = function(filter_string, plist){
  	
  	// Split the incoming filter string into its component parts.
  	var f_v = bbop.first_split(':', filter_string);
  	var fname = f_v[0];
  	var fval = f_v[1];
  
  	// Need to shuck the value from the quotes, as in load_url.
  	fval = bbop.dequote(fval);
  
  	var props = null;
  	if( us.isArray(plist) ){
  	    props = plist;
  	}else{
  	    props = [];
  	}
  
  	// Only continue on sensible inputs.
  	var ret = {};
  	if( fname !== '' && fval !== '' ){
  
  	    // Similar to the URL loader.
  	    var lead_char = fname.charAt(0);
  	    if( lead_char === '-' || lead_char === '+' ){
  		props.push(lead_char);
  		fname = fname.substr(1, fname.length -1);
  	    }
  	    
  	    ret = this.add_query_filter(fname, fval, props);
  	}
  
  	return ret;
      };
  
      /*
       * Function: add_query_filter
       *
       * Setter for query filters ('fq').
       *
       * Parameters: 
       *  filter - filter (type) string
       *  value - filter value string (or TODO: defined logic hash)
       *  plist - *[optional]* list of properties of the filter
       *
       * Returns: 
       *  (TODO) The current query filter hash.
       * 
       * See also:
       *  <plist_to_property_hash>
       */
      this.add_query_filter = function(filter, value, plist){
  	
  	// Make sure we've defined the group.
  	if( typeof(this.query_filters[filter]) === 'undefined' ){
  	    this.query_filters[filter] = {};
  	}
  
  	this.query_filters[filter][value] = this.plist_to_property_hash(plist);
  	
  	//ll("Current state: " + bbop.dump(this.query_filters));
  
  	return {}; // TODO
      };
  
      /*
       * Function: remove_query_filter
       *
       * Remover for query filters ('fq'), is a plist is specified, it
       * will only remove if all of the listed criteria are met.
       *
       * Parameters: 
       *  filter - filter (type) string
       *  value - filter value string (TODO: or defined logic hash)
       *  plist - *[optional]* list of properties of the filter
       *
       * Returns: 
       *  boolean (on success)
       */
      this.remove_query_filter = function(filter, value, plist){
  
  	// Default return value.
  	var retval = false;
  
  	// Internal helper to delete a low level key, and then if the
  	// top-level is empty, get that one too.
  	function _full_delete(hash, key1, key2){
  	    if( key1 && key2 && hash &&
  		hash[key1] && hash[key1][key2] ){
  		    delete hash[key1][key2];
  		}
  	    if( us.isEmpty(hash[key1]) ){
  		delete hash[key1];
  	    }
  	}
  
  	// If we have a filter, a value, and it's there...
  	if( filter && value &&
  	    anchor.query_filters[filter] &&
  	    anchor.query_filters[filter][value] ){
  
  		// If no real plist hash been defined, just go ahead
  		// and get rid of that. Otherwise, make sure that the
  		// defined plist and the stored properties are the
  		// same before deleting.
  		if( ! plist || us.isEmpty(plist) ){
  		    _full_delete(anchor.query_filters, filter, value);
  		    retval = true;
  		}else{
  		    
  		    var filter_phash = anchor.query_filters[filter][value];
  		    var in_phash = anchor.plist_to_property_hash(plist);
  		    
  		    if( bbop.is_same(filter_phash, in_phash) ){		
  			_full_delete(anchor.query_filters, filter, value);
  			retval = true;
  		    }
  		}
  	    }
  
  	return retval;
      };
  
      /*
       * Function: reset_query_filters
       *
       * Reset the query filters ('fq'); but leave sticky filters alone.
       *
       * Parameters: 
       *  n/a
       * 
       * Returns: 
       *  (TODO) The current query filter hash.
       */
      this.reset_query_filters = function(){
  
  	// Drill down and delete all non-stickies.
  	each(anchor.query_filters, function(values, filter){
  	    //ll('filter: ' + filter);
  	    each(values, function(props, value){
  		//ll('  value: ' + value);
  		var sticky_p = props['sticky_p'];
  		if( ! sticky_p ){
  		    //ll('hit: ' + filter + ', ' + value);
  		    anchor.remove_query_filter(filter, value);
  		}
  	    });
  	});
  	
  	return {}; // TODO
      };
  
      /*
       * Function: get_query_filter_properties
       *
       * Get a hash representing a query filter ('fq').
       *
       * Parameters: 
       *  key - filter string (TODO: or defined logic hash)
       *
       * Returns: 
       *  The current query filter hash for key.
       */
      this.get_query_filter_properties = function(filter, value){
  
  	// Default return value.
  	var retobj = null;
  	
  	// If we have a key and it's there...
  	var aqf = anchor.query_filters;
  	if( filter && value && aqf[filter] && aqf[filter][value] ){
  	    retobj =
  		{
  		    'filter' : filter,
  		    'value' : value,
  		    //'polarity': aqf[filter][value]['negative_p'],
  		    'negative_p': aqf[filter][value]['negative_p'],
  		    'sticky_p': aqf[filter][value]['sticky_p']
  		};
  	}
  
  	return retobj;
      };
  
      /*
       * Function: get_query_filters
       *
       * Get a list of hashes representing the query filters ('fq'). The
       * return lists look like:
       *
       * : [{'filter': A, 'value': B, 'negative_p': C, 'sticky_p': D}, ...]
       *
       * Where A and B are strings and C and D are booleans.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns: 
       *  A list of the current query filter hashs.
       */
      this.get_query_filters = function(){
  
  	var retlist = [];	
  	each(anchor.query_filters, function(values, f){
  	    each(values, function(props, v){
  		retlist.push(anchor.get_query_filter_properties(f, v));
  	    });
  	});
  
  	return retlist;
      };
  
      /*
       * Function: get_sticky_query_filters
       *
       * Get a list of hashes representing the current stucky query
       * filters ('fq'). See <get_query_filters> for a specification of
       * what the return type looks like.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns: 
       *  A list of the current sticky query filter hashs.
       * 
       * See also:
       *  <get_query_filters>
       */
      this.get_sticky_query_filters = function(){
  
  	var retlist = [];	
  	each(anchor.query_filters, function(values, f){
  	    each(values, function(props, v){
  		var qfp = anchor.get_query_filter_properties(f, v);
  		if( qfp['sticky_p'] === true ){
  		    retlist.push(qfp);			      
  		}
  	    });
  	});
  
  	return retlist;
      };
  
      // A little extra thing that we might need sometimes.
      this.query_extra = null;
  
      // Spaces can cause problems in URLs in some environments.
      //final_qurl = final_qurl.replace(/ /g, '%20');
      // Convert the URL into something more usable.
      // Because we internally use %09 as a special case, make sure
      // we don't double-up on it.
      this._query_encode = function(str_to_encode){
  
  	var fs1 = encodeURI(str_to_encode);
  	var fs2 = fs1.replace(/\%2509/g, '%09');
  
  	var final_encoding = fs2;
  	return final_encoding;
      };
  
      /*
       * Function: filter_list_to_assemble_hash
       *
       * Get all of our query filter variables and try and make
       * something of them that <get_assemble> can understand.
       *
       * Sticky doesn't matter here, but negativity does. However, we
       * can be pretty naive since the hashing should have already taken
       * out mutually exclusive dupes.
       * 
       * The argument is a list of query filter properties, as returned
       * by <get_query_filters> and <get_sticky_query_filters>.
       *
       * Parameters:
       *  flist - a list of query filter properties (see above)
       *
       * Returns:
       *  hash of filter names to value lists
       * 
       * See also:
       *  <get_query_filters>
       *  <get_sticky_query_filters>
       */
      this.filter_list_to_assemble_hash = function(flist){
  	var h = {};
  	each(flist, function(filter_property){
  	    
  	    // Grab only the properties that affect the
  	    // URL.
  	    var filter = filter_property['filter'];
  	    var value = filter_property['value'];
  	    var negative_p = filter_property['negative_p'];
  	    
  	    // We need to alter at the filter level.
  	    if( negative_p ){
  		filter = '-' + filter;
  	    }
  	    
  	    // Make sure it is defined.
  	    if( typeof(h[filter]) === 'undefined' ){
  		h[filter] = [];
  	    }
  	    h[filter].push(value);
  	});
  	return h;
      };
      
      /*
       * Function: sensible_query_p
       * 
       * Simply ask the manager if a free text query ('q') makes sense
       * at this point.
       * 
       * This currently means that the query text ('q') is one of:
       *  1) the same as the default query
       *  2) the same as the fundamental query
       *  3) three (3) (or whatever minimal_query is set to) characters long
       *  4) the empty string ('')
       * and that query fields ('qf') are defined.
       * 
       * This is an overridable opinion of the manager.
       * 
       * Parameters:
       *  n/a
       *
       * Returns:
       *  boolean
       */
      this.sensible_query_p = function(){
  	var retval = false;
  	var q = anchor.get_query();
  	var qf = anchor.query_field_set();
  
  	//console.log('q', q);
  	//console.log('qf', qf);
  
  	if( qf && ! us.isEmpty(qf) ){ // first hurdle
  
  	    if( q === anchor.get_default_query() ){
  		retval = true;
  	    }else if( q === anchor.get_fundamental_query() ){
  		retval = true;
  	    }else if( q && q.length >= anchor.minimal_query_length ){
  		retval = true;
  	    }else if( q === ''){
  		retval = true;
  	    }
  	}
  	return retval;
      };
  
      /*
       * Function: last_packet_sent
       *
       * It is up to the UI to do something interesting with this number.
       * 
       * Also remember that this number only rises through calls to
       * <update> or one of its wrappers. Calls to <get_query_url> and
       * the like will not affect this number.
       * 
       * Parameters:
       *  n/a 
       *
       * Returns:
       *  integer
       * 
       * See also:
       *  <update>
       */
      this.last_packet_sent = function(){
      	return anchor.last_sent_packet;
      };
  
      /*
       * Function: clear
       *
       * Clear all non-sticky query parameters to get back to a more
       * "original" state.
       * 
       * Not to be confused with <reset>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  n/a
       */
      this.clear = function(){
  
  	// Reset 'q'.
  	anchor.query = anchor.default_query;
  
  	// Reset 'fq', all but sticky.
  	anchor.reset_query_filters();
      };
  
      /*
       * Function: reset
       *
       * Manually trigger the "reset" chain of events.
       *
       * This is a curried wrapper for <update> and should be preferred
       * over a direct call to update.
       *
       * Note to be confused with <clear>.
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <update>
       */
      this.reset = function(){
  	return anchor.update('reset');
      };
  
      /*
       * Function: search
       *
       * Trigger the "search" chain of events.
       * Takes a field-keyed hash of bbop.logics as an argument.
       * 
       * This is a curried wrapper for <update> and should be preferred
       * over a direct call to update.
       * 
       * Parameters:
       *  n/a
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <update>
       */
      this.search = function(){
  	return anchor.update('search');
      };
  
      /*
       * Function: page
       *
       * Re-trigger the "search" chain of events, but with the variables
       * set for a different section of the results.
       * 
       * Note that this operates independently of any impossibilites in
       * the results--just how such paging would look and
       * triggering. Ths UI should handle impossibilities and the like.
       * 
       * This is a wrapper for <update> and should be preferred over a
       * direct call to update.
       * 
       * Parameters: 
       *  rows - the number of rows to return
       *  start - the offset of the rows to return
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <update>
       */
      this.page = function(rows, start){
  	anchor.set('rows', rows);
  	anchor.set('start', start);
  	return anchor.update('search', rows, start);
      };
  
      /*
       * Function: page_first
       *
       * Currently a convenience alias for <search>. Think about it--it
       * makes sense.
       * 
       * This is a wrapper for <page> and should be preferred over a
       * direct call to page.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  n/a
       * 
       * See also:
       *  <page>
       */
      this.page_first = anchor.search;
      
      /*
       * Function: page_previous
       * 
       * This is a wrapper for <page> and should be preferred over a
       * direct call to page.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <page>
       */
      this.page_previous = function(){
  	var do_rows = anchor.get_page_rows();
  	var do_offset = anchor.get_page_start() - do_rows;
  	return anchor.page(do_rows, do_offset);
      };
      
      /*
       * Function: page_next
       * 
       * This is a wrapper for <page> and should be preferred over a
       * direct call to page.
       * 
       * Parameters: 
       *  the query url (with the jQuery callback specific parameters)
       *
       * Returns:
       *  n/a
       * 
       * See also:
       *  <page>
       */
      this.page_next = function(){
  	var do_rows = anchor.get_page_rows();
  	var do_offset = anchor.get_page_start() + do_rows;
  	return anchor.page(do_rows, do_offset);
      };
      
      /*
       * Function: page_last
       * 
       * Trigger search on last page parameters.
       * 
       * Since the manager has no idea about what is actually being
       * returned, the real world number of total documents needs to be
       * added as an argument.
       * 
       * This is a wrapper for <page> and should be preferred over a
       * direct call to page.
       * 
       * Parameters: 
       *  total_document_count - integer for the total number of docs found
       *
       * Returns:
       *  the query url (with the jQuery callback specific parameters)
       * 
       * See also:
       *  <page>
       */
      this.page_last = function(total_document_count){
  	var do_rows = anchor.get_page_rows();
  	var mod = total_document_count % do_rows;
  	var do_offset = total_document_count - mod;
  	// ll("page_last: " + total_document_count + " " +
  	//    do_rows + " " + mod + " " + do_offset);
  	var ret = null;
  	if( mod === 0 ){
  	    ret = anchor.page(do_rows, do_offset - do_rows);
  	}else{
  	    ret = anchor.page(do_rows, do_offset);
  	}
  	return ret;
      };
  
      /*
       * Function: get_page_rows
       *
       * Return the number of rows the manager is currently set
       * to. Useful as an argument to <page>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  integer; the number of rows the manager is currently set to
       * 
       * See also:
       *  <page>
       */
      this.get_page_rows = function(){
  	return anchor.get('rows');
      };
  
      /*
       * Function: get_page_start
       *
       * Return the rows offset the manager is currently set to. Useful
       * as an argument to <page>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  integer; the offset the manager is currently set to
       * 
       * See also:
       *  <page>
       */
      this.get_page_start = function(){
  	return anchor.get('start');
      };
  
      /*
       * Function: add_query_field
       * 
       * Add a new query field to the query. 
       * 
       * This does not go through and expand into searchable fields, for
       * that see: <query_field_set>.
       *
       * Parameters: 
       *  qf - the query field to add
       *  boost - *[optional]* defaults to 1.0
       *
       * Returns:
       *  true or false on whether or not it is a new field
       * 
       * See also:
       *  <query_field_set>
       */
      this.add_query_field = function(qf, boost){
  	
  	var retval = false;
  
  	// Make sure that some boost is there.
  	if( typeof(boost) === 'undefined' ){
  	    boost = 1.0;
  	}
  
  	// Check.
  	if( typeof(anchor.query_fields[qf]) === 'undefined' ){
  	    retval = true;
  	}
  
  	// Add.
  	anchor.query_fields[qf] = boost;
  
  	return retval;
      };
  
      /*
       * Function: query_field_set
       *
       * Bulk getter/setter for the query fields--the fields that are
       * searched (and by what weight) when using a query ('q' or
       * set_query(), i.e. the 'qf' field).
       * 
       * This will always use searchable fields if possible,
       * automatically replacing the non-searchable versions (I can't
       * think of any reason to use non-searchable versions unless you
       * want your searches to not work) if a personality is set. If no
       * personality is set, it will just use the arguments as-is.
       * 
       * The argument replaces the current set.
       *
       * The qfs argument should be a hash like:
       * 
       *  {'field01': value01, ...}
       * 
       * Parameters: 
       *  qfs - *[optional]* query fields to set
       *
       * Returns:
       *  the current query_fields array (e.g. ["field01^value01", ...])
       */
      this.query_field_set = function(qfs){
  
  	// Covenience.
  	var cclass = anchor._current_class;
  
  	// Only do something if we have a query field set.
  	if( qfs ){
  	    
  	    // Only do the probing if a personality has been set.
  	    if( cclass ){
  
  		// Get the current searchable extension string from
  		// the personality class.
  		//var s_ext = cclass.searchable_extension();
  		// Actually, we're going to make this non-variable.
  		var s_ext = '_searchable';
  
  		// Probe the input to see if there are any searchable
  		// alternatives to try, use those instead.
  		var searchable_qfs = {};
  		each(qfs, function(value, filter){
  		    // If the probe fails, just put in
  		    // whatever is there.
  		    var cfield = cclass.get_field(filter);
  		    if( cfield && cfield.searchable() ){
  			//ll('filter/value:');
  			var new_f = filter + s_ext;
  			searchable_qfs[new_f] = value;
  		    }else{
  			searchable_qfs[filter] = value;
  		    }
  	    	});
  		qfs = searchable_qfs;
  	    }	    
  	    
  	    // Overwrite the current.
  	    anchor.query_fields = qfs;
  	}
  	
  	// Using the original information, convert them to the
  	// proper output format.
  	var output_format = [];
  	each(anchor.query_fields, function(value, filter){
  	    output_format.push(filter + '^' + value);
  	});
  	return output_format;
      };
  
      /*
       * Function: facets
       *
       * Bulk getter/setter for facets (technically 'facet.field').
       *
       * Parameters: 
       *  key - *[optional]* facet to add to the facet list
       *
       * Parameters: 
       *  list - *[optional]* list to replace the current list with
       *
       * Returns:
       *  the current facets hash.
       */
      this.facets = function(list_or_key){
  	if( list_or_key ){
  	    if( bbop.what_is(list_or_key) !== 'array' ){
  		// Arrayify it.
  		list_or_key = [list_or_key];
  	    }else{
  		// When there is a list, we are replacing the whole
  		// thing, so let's just poof it out of existance.
  		anchor.facet_fields = {};
  	    }
  	    each(list_or_key, function(item){
  		anchor.facet_fields[item] = true;
  	    });
  	}
  	return us.keys(anchor.facet_fields);
      };
  
      /*
       * Function: set_default_query
       *
       * Setter for the default query for the query variable ('q').
       * 
       * Call <reset_query> if you want to affect query immediately.
       * 
       * Parameters: 
       *  new_default_query - new default query string (or TODO: <bbop.logic>)
       *
       * Returns:
       *  the current setting of default query for ('q')
       */
      this.set_default_query = function(new_default_query){
  	anchor.default_query = new_default_query;
  	return anchor.default_query;
      };
  
      // /*
      //  * Function: set_first_run_query
      //  *
      //  * Setter for a first run query.  Normally, when <reset_query>, or
      //  * related method, is executed, we reset back to the default
      //  * query. This method sets a one time variable so a non empty
      //  * value can be used for the first reset.
      //  * 
      //  * Call <reset_query> if you want to affect query immediately.
      //  * 
      //  * Parameters: 
      //  *  first_run_query - query_string (or TODO: <bbop.logic>)
      //  *
      //  * Returns:
      //  *  the current setting of default query for ('q')
      //  */
      // this.set_first_run_query = function(first_run_query){
      // 	anchor.default_query = new_default_query;
      // 	return anchor.default_query;
      // };
  
      /*
       * Function: reset_default_query
       *
       * Reset the default query back to "*:*".
       * 
       * Call <reset_query> if you want to affect query immediately.
       * 
       * Parameters:
       *  n/a
       *
       * Returns:
       *  the current setting of default query ('q')
       */
      this.reset_default_query = function(){
  	anchor.default_query = anchor.fundamental_query;
  	return anchor.default_query;
      };
  
      /*
       * Function: set_query
       *
       * Setter for the query variable ('q').
       * 
       * Parameters: 
       *  new_query - new value for the query string (or TODO: <bbop.logic>)
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_comfy_query>
       */
      this.set_query = function(new_query){
  	anchor.query = new_query;
  	return anchor.query;
      };
  
      /*
       * Function: set_comfy_query
       *
       * A specialized setter for the query variable ('q'), as follows:
       *
       * If the input is all alphanum or space, the input is
       * tokenized. If there is one token, if it is at least three
       * characters, gets a wildcard '*'; if there are more tokens, the
       * last one gets a wild card.
       * 
       * This might be a more comfortable way to search for most naive
       * (non-power user) interfaces.
       * 
       * Parameters: 
       *  new_query - new value for the query string (or TODO: <bbop.logic>)
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_query>
       */
      this.set_comfy_query = function(new_query){
  
  	var comfy_query = new_query;
  
  	// Check that there is something there.
  	if( new_query && new_query.length && new_query.length > 0 ){
  
  	    // Check if the last real input has a space after it.
  	    var has_cursor_p = true;
  	    if( new_query.slice(-1) === ' ' ){
  		has_cursor_p = false;
  	    }
  
  	    // Now chomp it down again to get rid of whitespace.
  	    new_query = bbop.chomp(new_query);
  
  	    // Check (again) that there is something there.
  	    if( new_query && new_query.length && new_query.length > 0 ){
  
  		// That it is alphanum+space-ish and that we actually
  		// might want to add a wildcard (i.e. has cursor).
  		if( alphanum.test(new_query) && has_cursor_p ){
  	    
  		    // Break it into tokens and get the last.
  		    var tokens = new_query.split(new RegExp('\\s+'));
  		    var last_token = tokens[tokens.length -1];
  		    //ll('last: ' + last_token);
  		
  		    if( tokens.length === 1 ){
  			
  			// If it is three or more, add the wildcard.
  			if( last_token.length >= anchor.minimal_query_length ){
  			    tokens[tokens.length -1] = last_token + '*';
  			}
  		    }else{
  			tokens[tokens.length -1] = last_token + '*';
  		    }
  		    // And join it all back into our comfy query.
  		    comfy_query = tokens.join(' ');
  		}
  	    }
  	}
  
  	// Kick it back to the normal set_query.
  	return anchor.set_query(comfy_query);
      };
  
      /*
       * Function: set_id
       *
       * A limited setter, removing whatever else is on query. This is
       * for when you want to lock into one (unique) document by id
       * (essentially 'q=id:"foo"'). All other query operations behave
       * as they should around it.
       * 
       * Parameters: 
       *  new_id - string id
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_ids>
       */
      this.set_id = function(new_id){
  	anchor.query = 'id:' + bbop.ensure(new_id, '"');
  	return anchor.query;
      };
  
      // Function to unwind and lock a list if identifiers onto a field.
      function _lock_map(field, id_list){
  	var fixed_list = [];
  	each(id_list, function(item){
  	    fixed_list.push(bbop.ensure(item, '"'));
  	});
  	
  	var base_id_list = '(' + fixed_list.join(' OR ') + ')';
  
  	var ret_query = field + ':' + base_id_list;
  	return ret_query;
  	
      }
  
      /*
       * Function: set_ids
       *
       * Like <set_id>, a limited setter. It removes whatever else is on
       * query and replaces it with something like:
       * 
       * : gm.set_ids(['GO:1', 'GO:2'])
       * 
       * This is for when you want to lock into a set of documents by id. All
       * other query operations behave as they should around it.
       * 
       * Parameters: 
       *  id_list - a list of ids to search for
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_ids>
       */
      this.set_ids = function(id_list){
  	anchor.query = _lock_map('id', id_list);
  	return anchor.query;
      };
  
      /*
       * Function: set_targets
       *
       * Like a more generalized version of <set_ids>, a limited. It
       * removes whatever else is on query and replaces it with
       * something like:
       * 
       * : gm.set_targets(['GO:1', 'GO:2'], ['field_1', 'field_2'])
       * 
       * This is for when you want to lock into a set of documents by
       * locking onto identifiers in some set of search fields. All
       * other query operations behave as they should around it.
       * 
       * Parameters: 
       *  id_list - a list of ids to search for
       *  field_list - a list of fields ids to search across
       *
       * Returns:
       *  the current setting of query ('q')
       * 
       * Also see:
       *  <set_ids>
       */
      this.set_targets = function(id_list, field_list){
  
  	var fixed_list = [];
  	each(field_list, function(field){
  	    fixed_list.push(_lock_map(field, id_list));
  	});
  
  	var sum = fixed_list.join(' OR ');
  
  	anchor.query = sum;
  	return anchor.query;
      };
  
      /*
       * Function: get_query
       *
       * Getter for the query variable ('q').
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of extra
       */
      this.get_query = function(){
  	return anchor.query;
      };
  
      /*
       * Function: get_default_query
       *
       * Getter for what the query variable 'q' will be set to on a
       * <reset_query>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of the default query
       */
      this.get_default_query = function(){
  	return anchor.default_query;
      };
  
      /*
       * Function: get_fundamental_query
       *
       * Getter for what the query variable 'q' will be set to on a
       * <reset_default_query>.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of the fundamental default query
       */
      this.get_fundamental_query = function(){
  	return anchor.fundamental_query;
      };
  
      /*
       * Function: get_query
       *
       * Getter for the query variable ('q').
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of extra
       */
      this.get_query = function(){
  	return anchor.query;
      };
  
      /*
       * Function: reset_query
       *
       * Remove/reset the query variable ('q'); this set it back to the
       * default query.
       *
       * Parameters:
       *  none
       *
       * Returns:
       *  the current value of query
       * 
       * Also see:
       *  <set_default_query>
       *  <reset_default_query>
       */
      this.reset_query = function(){
  	anchor.query = anchor.default_query;
  	ll('reset query to default: ' + anchor.query);
  	return anchor.query;
      };
  
      /*
       * Function: set_extra
       *
       * Setter for the internal string variable to be appended to the
       * end of a query. For special use cases only (e.g. extend
       * functionality of the API safely).
       * 
       * Parameters: 
       *  new_extra - *[optional]* new value for the extras string
       *
       * Returns:
       *  the current setting of extra
       */
      this.set_extra = function(new_extra){
  	anchor.query_extra = new_extra;
  	return anchor.query_extra;
      };
  
      /*
       * Function: get_extra
       *
       * Getter for the internal string variable to be appended
       * to the end of a query.
       *
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  the current setting of extra
       */
      this.get_extra = anchor.set_extra;
  
      /*
       * Function: remove_extra
       *
       * Remove/reset the extra bit.
       *
       * Parameters:
       *  none
       *
       * Returns:
       *  ""
       */
      this.remove_extra = function(){
  	anchor.query_extra = "";
  	return anchor.query_extra;
      };
  
      /*
       * Function: set
       *
       * Set an internal variable for the query. The internal variables
       * are typically things like 'qt', 'indent', etc.--things that you
       * might set and forget a while. It does /not/ include highly
       * dynamic variables (like callback and packet) or querying
       * variables like 'q' and 'fq'; for those you need to use the API.
       *
       * Parameters: 
       *  key - the name of the parameter to change
       *  new_val - what you want the new value to be
       *
       * Returns:
       *  n/a
       */
      this.set = function(key, new_val){
  	anchor.query_variants[key] = new_val;
      };
  
      /*
       * Function: get
       *
       * Get an internal variable for the query.
       *
       * See <set> for the kinds of parameters that can be read.
       * 
       * Parameters: 
       *  key - the name of the parameter to get
       *
       * Returns:
       *  The found value of the key.
       */
      this.get = function(key){
  	return anchor.query_variants[key];
      };
  
      /*
       * Function: unset
       *
       * Unset (remove) an internal variable for the query. Only usable on certain types of 
       * 
       * Only use is you really know what you're doing.
       *
       * Parameters: 
       *  key - the name of the parameter to unset/remove
       *
       * Returns:
       *  boolean; true false on whether the key was found
       */
      this.unset = function(key){
  	var retval = false;
  
  	if( typeof(anchor.query_variants[key]) !== 'undefined' ){
  	    retval = true;
  	    delete anchor.query_variants[key];
  	}
  
  	return retval;
      };
  
      /*
       * Function: include_highlighting
       *
       * Turn hilighting on or off (with true or false).
       * 
       * This essentially adds the parameters to the query string to
       * make sure that basic highlighting on the search is returned.
       * 
       * It starts off as false. The optional html_elt_str argument
       * defaults to:
       *  : <em class="hilite">
       *
       * Parameters: 
       *  hilite_p - *[optional]* boolean
       *  html_elt_str - *[serially optional]* the HTML element string to use
       *
       * Returns:
       *  either false or the current string being used for the return element
       */
      this.include_highlighting = function(hilite_p, html_elt_str){
  	var retval = false;
  
  	if( typeof(hilite_p) !== 'undefined' &&
  	    (hilite_p === true || hilite_p === false) ){
  	    if( hilite_p === true ){
  
  		// Set the default string if necessary.
  		if( ! html_elt_str ){ html_elt_str = '<em class="hilite">'; }
  
  		// Set the parameters.
  		anchor.set('hl', 'true');
  		anchor.set('hl.simple.pre', html_elt_str);
  
          anchor.set('hl.snippets', anchor.default_hl_snippets);
  
  		// And the retval is not longer false.
  		retval = html_elt_str;
  
  	    }else{
  		
  		// Unset the parameters.
  		anchor.unset('hl');
  		anchor.unset('hl.simple.pre');
  		anchor.unset('hl.snippets');
  	    }
  
  	}else{
  	    // Otherwise, just discover the current state and return
  	    // it.
  	    var cl_tmp = anchor.get('hl.simple.pre');
  	    if( typeof(cl_tmp) !== 'undefined' ){
  		retval = cl_tmp;
  	    }
  	}
  
  	return retval;
      };
  
      /*
       * Function: set_personality
       *
       * While we are always contacting the same Solr instance, we
       * sometimes want to have different weights, facets, etc. This
       * function allows us to use the pre-set ones defined in the
       * constructor configuration argument.
       * 
       * Currently, this only sets the 'facet.field' internal variable.
       *
       * Parameters: 
       *  personality_id - string
       *
       * Returns:
       *  Will return false if personality doesn't exist
       */
      this.set_personality = function(personality_id){
  	var retval = false;
  
  	// This sets the facet.field internal variable.
  	var cclass = anchor._golr_conf.get_class(personality_id);
  	if( cclass ){
  
  	    // Remember what our personality is.
  	    // WARNING: this line must go before the query_field_set
  	    // line below, or else we won't get the "smart" search.
  	    this._current_class = cclass;
  
  	    // Set the facets for our class.
  	    anchor.facets(cclass.field_order_by_weight('filter'));
  
  	    // Set the query field weights ('qf') necessary to make
  	    // queries run properly.
  	    anchor.query_field_set(cclass.get_weights('boost'));
  	    
  	    // Show that we did indeed set a personality.
  	    retval = true;
  	}
  
  	return retval;
      };
  
      /*
       * Function: get_personality
       *
       * Returns the current personality, null if none.
       * 
       * Parameters: 
       *  n/a
       *
       * Returns:
       *  Returns the current personality as a string, null if none is set
       */
      this.get_personality = function(){
  	var retval = null;
  
  	if( typeof(anchor._current_class) !== 'undefined' &&
  	    bbop.what_is(anchor._current_class) === 'golr-conf.conf_class'){
  	    retval = anchor._current_class.id();
  	}
  
  	return retval;
      };
  
      /*
       * Function: get_query_url
       *
       * Get the current invariant state of the manager returned as a
       * encoded URL string (using encodeURI()).
       * 
       * This means the URL for the current query to the GOlr store, but
       * without extra information about packets, callbacks, and the
       * like.
       * 
       * This is generally appropriate for getting data, but maybe not
       * for things like high-speed autocomplete where races can
       * occur. For those, you might want to consider <update> or
       * <search>.
       *
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  URL string
       * 
       * Also see:
       *  <update>, <search>
       */
      this.get_query_url = function(){
  
  	// Structure of the necessary invariant parts.	
  	var qurl = anchor._solr_url + 'select?';
  
  	// Filters to assemble.
  	var assemf = anchor.get_query_filters();
  	var fq = anchor.filter_list_to_assemble_hash(assemf);
  
  	// Add all of our different specialized hashes.
  	var things_to_add = [
  	    //bbop.get_assemble(anchor.query_invariants),
  	    //bbop.get_assemble(anchor.query_facets),
  	    bbop.get_assemble(anchor.query_variants),
  	    bbop.get_assemble(anchor.current_facet_field_limits),
  	    //bbop.get_assemble({'fq': anchor.query_sticky_filters}),
  	    bbop.get_assemble({'fq': fq}),
  	    bbop.get_assemble({'facet.field':
  			       us.keys(anchor.facet_fields)}),
  	    bbop.get_assemble({'q': anchor.query}),
  	    anchor.query_extra
  	];
  	// Add query_fields ('qf') iff query ('q') is set and it is
  	// not length 0.
  	if( anchor.query &&
  	    anchor.query.length &&
  	    anchor.query.length !== 0 &&
  	    anchor.query !== anchor.fundamental_query ){
  		var in_qf =
  		    bbop.get_assemble({'qf': anchor.query_field_set()});
  		things_to_add.push(in_qf);
  	    }
  	
  	// Assemble the assemblies into a single URL, throw out
  	// everything that seems like it isn't real to keep the URL as
  	// clean a possible.
  	var filtered_things =
  		bbop.pare(things_to_add, function(item, index){
  		    var retval = true;
  		    if( item && item !== '' ){
  			retval = false;
  		    }
  		    return retval;
  		});
  
  	var final_qurl = qurl + filtered_things.join('&');
  	final_qurl = anchor._query_encode(final_qurl);
  	ll('qurl: ' + final_qurl);
      	return final_qurl;
      };
  
      /*
       * Function: push_excursion
       *
       * Save the current state of the manager--data and sticky filter
       * information--onto an internal stack. Batch information is not
       * stored.
       * 
       * Useful for gettinginto a state, doing something else, then
       * returning to the original state.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  the number of items on the excursion stack
       * 
       * Also see:
       *  <get_query_url>
       *  <pop_excursion>
       */
      this.push_excursion = function(){
  	
  	var now = {
  	    // Save current state (data).
  	    data_url: anchor.get_query_url(),
  	    // Save current state (session).
  	    session: {
  		// Get the sticky filters.
  		sticky_filters: anchor.get_sticky_query_filters()
  	    }
  	};
  
  	// Save.
  	anchor._excursions.push(now);
  
  	// ...
      	return anchor._excursions.length;
      };
  
      /*
       * Function: pop_excursion
       *
       * Return to a previously pushed state. Batch items are not
       * recovered.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  boolean on whether a state was recovered
       * 
       * Also see:
       *  <get_query_url>
       *  <gpush_excursion>
       */
      this.pop_excursion = function(){
  	
  	var retval = false;
  
  	var then = anchor._excursions.pop();
  	if( then ){
  	    retval = true;
  
  	    // Recover data state.
  	    var then_data_url = then['data_url'];
  	    anchor.load_url(then_data_url);
  
  	    // Recover the session state.
  	    var then_session_stickies = then['session']['sticky_filters'];
  	    // Add the sticky filters.
  	    each(then_session_stickies, function(sticky){
  		var flt = sticky['filter'];
  		var fvl = sticky['value'];
  		var fpl = [];
  		if( sticky['negative_p'] === true ){
  		    fpl.push('-');
  		}
  		if( sticky['sticky_p'] === true ){
  		    fpl.push('*');
  		}
  		anchor.add_query_filter(flt, fvl, fpl);
  	    });	    
  	}
  	
      	return retval;
      };
  
      /*
       * Function: get_download_url
       *
       * Get the current invariant state of the manager returned as a
       * URL string.
       * 
       * This differs from <get_query_url> in that the generated string
       * is intended for text-processing uses rather than computerized
       * searching uses. The idea where is to create a TSV file for
       * downloading and consumption.
       * 
       * Instead of downloading all of the results, a limited listed set
       * can be downloaded using entity_list, which identifies documents by id.
       * 
       * The optional argument hash looks like:
       *  rows - the number of rows to return; defaults to: 1000
       *  encapsulator - how to enclose whitespace fields; defaults to: ""
       *  separator - separator between fields; defaults to: "%09" (tab)
       *  header - whether or not to show headers; defaults to: "false"
       *  mv_separator - separator for multi-valued fields; defaults to: "|"
       *  entity_list - list of specific download items in results; default null
       * 
       * With the entity list, keep in mind that null and an empty list
       * are handled in pretty much the same way--they are an indication
       * that we are going after nothing specific, and so all results
       * are game.
       * 
       * Parameters:
       *  field_list - a list of fields to return
       *  in_arg_hash - *[optional]* additional optional arguments
       * 
       * Returns:
       *  URL string
       * 
       * Also see:
       *  <get_query_url>
       */
      this.get_download_url = function(field_list, in_arg_hash){
  	
  	// Save current state.
  	anchor.push_excursion();
  
  	// Deal with getting arguments in properly.
  	var default_hash =
  	    {
  		rows : 1000,
  		encapsulator : '',
  		separator : "%09",
  		header : 'false',
  		mv_separator : "|",
  		entity_list : [],
  		golr_download_url : null
  	    };
  	var arg_hash = bbop.fold(default_hash, in_arg_hash);
  
  	// Make the changes we want.
  	anchor.set('wt', 'csv');
  	anchor.set('start', 0);
  	anchor.set('fl', field_list.join(','));
  	anchor.set('rows', arg_hash['rows']);
  	anchor.set('csv.encapsulator', arg_hash['encapsulator']);
  	anchor.set('csv.separator', arg_hash['separator']);
  	anchor.set('csv.header', arg_hash['header']);
  	anchor.set('csv.mv.separator', arg_hash['mv_separator']);
  
  	// A little more tricky, jimmy the entity list into the query
  	// if it's viable.
  	var entity_list = arg_hash['entity_list'];
  	if( typeof(entity_list) !== 'undefined' &&
  	    us.isArray(entity_list) &&
  	    entity_list.length > 0 ){
  		anchor.set_ids(entity_list);
  	}
  
  	// Get url.
  	var returl = anchor.get_query_url();
  
  	// If defined, switch download URL to something else.
  	if( arg_hash.golr_download_url ){
  	    returl = returl.replace(anchor._solr_url,
  				    arg_hash.golr_download_url);
  	}
  
  	// Reset the old state.
  	anchor.pop_excursion();
  
      	return returl;
      };
  
      /*
       * Function: get_filter_query_string
       *
       * Get the current state of the manager, as defined by the current
       * gross filter set--query, sticky filters, and standard filters--
       * returned as a URL query string (sans the '?').
       * 
       * This differs from <get_query_url> and <get_state_url> in that
       * the generated string is intended for applications that may want
       * just enough information to recover filter state when the
       * personality, and other types of information, are already
       * known. It is intended to be part of a light RESTy bookmarking
       * mechanism in larger application.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  query string for current filters (sans the '?')
       * 
       * Also see:
       *  <get_query_url>
       *  <get_state_url>
       */
      this.get_filter_query_string = function(){
  	
  	// // Save current state.
  	// anchor.push_excursion();
  
  	var q = anchor.get_query();
  
  	// Get the filters and sort them into sticky and "normal"
  	// sets.
  	var filters = anchor.get_query_filters();
  	var std_filters = [];
  	var sticky_filters = [];
  	each(filters, function(filter){
  	    if( filter['sticky_p'] ){
  		sticky_filters.push(filter);
  	    }else{
  		std_filters.push(filter);
  	    }
  	});
  	
  	var fq = anchor.filter_list_to_assemble_hash(std_filters);
  	var sfq = anchor.filter_list_to_assemble_hash(sticky_filters);
  
  	var things_to_add = [];
  	if( q ){
  	    things_to_add.push(bbop.get_assemble({'q': q}));
  	}
  	if( ! us.isEmpty(fq) ){
  	    things_to_add.push(bbop.get_assemble({'fq': fq}));
  	}
  	if( ! us.isEmpty(sfq) ){
  	    things_to_add.push(bbop.get_assemble({'sfq': sfq}));
  	}
  	    
  	// // Reset the old state.
  	// anchor.pop_excursion();
  
  	var final_qstr = things_to_add.join('&');
  	final_qstr = anchor._query_encode(final_qstr);
      	return final_qstr;
      };
  
      /*
       * Function: get_state_url
       *
       * Get the current invariant state of the manager, plus the
       * current personality as a parameter, returned as a URL string.
       * 
       * This differs from <get_query_url> in that the generated string
       * is intended for applications that may want a little more
       * information and hinting over just what the current search
       * is. This method essentially parameterizes some of the "hidden
       * state" of the manager.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  URL string
       * 
       * Also see:
       *  <get_query_url>
       */
      this.get_state_url = function(){
  	
  	// Save current state.
  	anchor.push_excursion();
  
  	// Make the changes we want. First, physically set the
  	// "personality", then set pins for jump-in recovery.
  	anchor.set('personality', anchor.get_personality());
  
  	// Explicitly set sticky pins for later recovery.
  	// Do this pretty much exactly like we do for get_query_url().
  	var sticky_filters = anchor.get_sticky_query_filters();
  	var sfq = anchor.filter_list_to_assemble_hash(sticky_filters);
  	anchor.set('sfq', sfq);
  	
  	// Get url.
  	var returl = anchor.get_query_url();
  
  	// Reset the old state.
  	anchor.pop_excursion();
  
      	return returl;
      };
  
      /*
       * Function: load_url
       *
       * Makes a a best attempt to recover the state of a manager from
       * the clues left in a data url. This can also (and probably
       * should) be thought of as a "load bookmark"
       * function. Theoretically, you should even be able to use
       * "bookmarks" from alien installations.
       * 
       * Note that while this recovers enough to get the same data,
       * certain "session"/"preference" type things that are not encoded
       * in the url (e.g. filter stickiness, the contents of batch
       * queues, non-default base queries, etc.) will not be replayed
       * and must be recovered or guessed on an app by app basis..
       * 
       * Warning: this currently only replays a small subset of possible
       * parameters. Currently: personality, q, fq, ???. In the future,
       * this should no all non-session information.
       * 
       * Warning: Because there is more to bookmarks than just the major
       * stuff, variants not supplied in the bookmark will be removed.
       * 
       * This returns true if the parameter portions of the new and
       * bookmark urls match. However, this is often not the case--think
       * shifting personalities, etc.
       * 
       * Parameters:
       *  url - A URL string generated by a manager's get_query_url (or similar)
       * 
       * Returns:
       *  boolean
       */
      this.load_url = function(url){
  
  	// // Some Regexps that would be nice to just compile once.
  	// var regexp_url_space = /\%20/g; // '%20' === ' '
  	// var regexp_url_quote = /\%22/g; // '%22' === '"'
  	// var regexp_url_left_paren = /\%28/g; // '%28' === '('
  	// var regexp_url_right_paren = /\%29/g; // '%29' === ')'
  
  	// We are assuming that we are consuming our own URLs from
  	// get_query_url(), so we start by attempting to decode it
  	// (TODO: need a tab watch here)?
  	var decoded_url = decodeURI(url);
  
  	// Break down url.
  	var in_params = bbop.url_parameters(decoded_url);
  
  	// First, look for the personality setting and invoke it if
  	// it's there--it will dominate unless we take care of it first.
  	// Also note the all the keys that we see (for later erasure
  	// of excess).
  	var seen_params = {};
  	each(in_params, function(ip){
  	    var key = ip[0];
  	    var val = ip[1];
  	    if( key === 'personality' && val && val !== '' ){
  		anchor.set_personality(val);
  	    }
  	    seen_params[key] = true;
  	});
  	
  	// Now cycle through the the parameters again and invoke the
  	// appropriate functions to bring them in line.
  	var sticky_cache = {};
  	each(in_params, function(ip){
  	    var key = ip[0];
  	    var val = ip[1];
  	    if( typeof(val) !== 'undefined' && val !== '' ){
  		if( key === 'personality' ){
  		    // Already did it, skip.
  		}else if( key === 'q' ){
  		    anchor.set_query(val);
  		}else if( key === 'fq' || key === 'sfq' ){
  		    // Split the fq (or sfq) parameter.
  		    var fnv = bbop.first_split(':', val);
  		    var fname = fnv[0];
  		    var fval = fnv[1];
  		    //ll('HERE: fname: ' + fname);
  		    //ll('HERE: fval: ' + fval);
  		    if( fname && fval ){
  			
  			var plist = [];
  			
  			// Remove leading sign on a filter and
  			// add it to the plist.
  			var lead_char = fname.charAt(0);
  			if( lead_char === '-' || lead_char === '+' ){
  			    plist.push(lead_char);
  			    fname = fname.substr(1, fname.length -1);
  			}
  			
  			// // TODO: 
  			// // If the fval looks like it has not been
  			// // decoded (like from a URL-safe
  			// // bookmark), go ahead and do so.
  			// fval = fval.replace(regexp_url_space, ' ');
  			// fval = fval.replace(regexp_url_quote, '"');
  			// fval = fval.replace(regexp_url_left_paren, '(');
  			// fval = fval.replace(regexp_url_right_paren,')');
  			
  			// Do not allow quotes in--they will be
  			// added by the assembler.
  			fval = bbop.dequote(fval);
  			
  			// Make it sticky it it came in on "sfq".
  			// Note if this is the sticky form.
  			var skey = fname + '^' + fval;
  			if( key === 'sfq' ){
  			    sticky_cache[skey] = true;
  			    plist.push('*');
  			}
  			
  			// Add the query filter properly, but
  			// only if we have not already added the
  			// sticky form (prevent clobbering).
  			if( ! bbop.is_defined(sticky_cache[skey]) ||
  			    key === 'sfq'){
  			    anchor.add_query_filter(fname, fval, plist);
  			    
  			}
  		    }
  		}else if( key === 'qf' ){
  		    // qf is handles a little strangely...
  		    var foo = bbop.first_split('^', val);
  		    //ll('qf: key: '+ key +', val: '+ val +', foo: '+ foo);
  		    anchor.add_query_field(foo[0], foo[1]);
  		}else if( key === 'facet.field' ){
  		    anchor.facets(val);
  		}else if( key === 'start' || key === 'rows' ){
  		    // Numbers need to be handled carefully.
  		    if( bbop.what_is(val) === 'string' ){
  			val = parseFloat(val);
  		    }
  		    anchor.set(key, val);
  		}else{
  		    // This one catches all of the non-special
  		    // parameters and resets them using .set().
  		    anchor.set(key, val);
  		    // if( key === 'fq' ){
  		    //     throw new Error("OI");			     
  		    // }
  		}
  	    }
  	});
  	
  	// Now go through and remove all of the query variant
  	// parameters that were not seen in the bookmark.
  	each(anchor.query_variants, function(val, key){
  	    if( typeof(seen_params[key]) === 'undefined'){
  		anchor.unset(key);
  	    }
  	});
  	
  	// Produce our own url from what we've done. If the parameters
  	// match with the incoming argument's return true.
  	var curr_url = anchor.get_query_url();
  	var curr_params = bbop.url_parameters(curr_url);
  	var differences = 0;
  	if( in_params.length === curr_params.length ){
  	    each(in_params, function(in_p, i){
  		var curr_p = curr_params[i];
  		if( in_p.length === curr_p.length ){
  		    if( in_p.length === 1 ){
  			if( in_p[0] === curr_p[0] ){
  			    // match!
  			}else{
  			    differences++;
  			}
  		    }else if( in_p.length === 2 ){
  			if( in_p[0] === curr_p[0] && in_p[1] === curr_p[1] ){
  			    // match!
  			}else{
  			    differences++;
  			}
  		    }
  		}else{
  		    differences++;
  		}
  	    });
  	}else{
  	    differences++;
  	}
  	
  	// Tally the differences and decides if they're the same.
  	var retval = false;
  	if( differences === 0 ){
  	    retval = true;
  	}
      	return retval;
      };
  
      /*
       * Function: add_to_batch
       *
       * "Save" the current manager state to run later in serial batch
       * mode.
       * 
       * The actual job of running these batches is left to the
       * implementation of the sub-managers; probably in "run_batch".
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  state url
       */
      this.add_to_batch = function(){
  	var qurl = anchor.get_query_url();
  	anchor._batch_urls.push(qurl);
      	return qurl;
      };
  
      /*
       * Function: batch_urls
       *
       * Return a pointer to the current batch urls.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  array
       */
      this.batch_urls = function(){
      	return anchor._batch_urls;
      };
  
      /*
       * Function: next_batch_url
       *
       * Return the next data to be processed, removing it from the
       * batch queue in the process.
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  state url or null
       */
      this.next_batch_url = function(){
      	return anchor._batch_urls.shift() || null;
      };
  
      /*
       * Function: reset_batch
       *
       * Clear the currently queued data batch.
       * 
       * The actual job of running these batches is left to the
       * implementation of the sub-managers; probably in "run_batch".
       * 
       * Parameters:
       *  n/a
       * 
       * Returns:
       *  the number of items cleared
       */
      this.reset_batch = function(){
  	var num = anchor._batch_urls.length;
  	anchor._batch_urls = [];
      	return num;
      };
  }
func_documentation_string: /*
  Package: manager.js
  
  Namespace: bbop.golr.manager
  
  Generic BBOP manager for dealing with gross GOlr configuration and
  management. Remember, this is actually a "subclass" of
  <bbop.registry>. The defined events for this registry are: "reset",
  "search", and "error".
  
  reset - functions for initializing and resetting
  search - functions for receiving standard search results
  error - functions to call when something goes very wrong
  
  Both <bbop.golr.response> (or clean error data) and the manager
  itself (this as anchor) should be passed to the callbacks.
  
  TODO/BUG: <set_query> and <set_default_query> should both take
  strings or <bbop.logic> as arguments. Those, as well as <get_query>
  and <get_query> should only return <bbop.logic>.
   /*
  Constructor: manager
  
  Contructor for the GOlr query manager
  
  Arguments:
  golr_loc - string url to GOlr server;
  golr_conf_obj - a <bbop.golr.conf> object
  
  Returns:
  golr manager object
  
  See also:
  <bbop.registry>
  
  A manager for handling the AJAX and registry. Initial take from
  {module:bbop-rest-manager}.
  
  @constructor
  @param {String} barista_location - string for invariant part of API
  @param {String} namespace - string for namespace of API to use
  @param {String} user_token - identifying string for the user of the manager (Barista token)
  @param {Object} engine - Remote resource manager client to use (must be an instantiated {module:bbop-rest-manager} engine)
  @param {String} mode - whether or not to have utility methods (most besides fetch_with and start_with be in); options are "sync" and "async", which correspond to internally using fetch and start respectively
  @returns {manager} a classic manager