text:
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Alexa.NET.Management.Nlu.AnnotationSet;
using Newtonsoft.Json.Linq;
using Refit;

namespace Alexa.NET.Management.Internals
{
    public class NluAnnotationSetApi : INluAnnotationSetApi
    {
        private IClientNluAnnotationSetApi Client { get; }

        public NluAnnotationSetApi(HttpClient httpClient)
        {
            Client = RestService.For<IClientNluAnnotationSetApi>(httpClient, ManagementRefitSettings.Create());
        }

        public Task<CreateAnnotationSetResponse> Create(string skillId, string locale, string name)
        {
            return Create(skillId, new CreateAnnotationSetRequest
            {
                Locale = locale,
                Name = name
            });
        }

        public Task<ListAnnotationSetResponse> List(string skillId, string locale = null, int? maxResults = null)
        {
            return List(skillId, null, locale, maxResults);
        }

        public Task<ListAnnotationSetResponse> List(string skillId, string nextToken, string locale = null, int? maxResults = null)
        {
            return Client.List(skillId, locale, maxResults, nextToken);
        }

        public Task<AnnotationSet> Get(string skillId, string annotationId)
        {
            return Client.Get(skillId, annotationId, "application/json");
        }

        public Task Update(string skillId, string annotationId, AnnotationSet set)
        {
            return Client.Update(skillId, annotationId, set);
        }

        public async Task Rename(string skillId, string annotationId, string name)
        {
            var response = await Client.Rename(skillId, annotationId, new UpdatePropertiesRequest { Name = name });

            if (response.StatusCode != HttpStatusCode.Created)
            {

                var body = string.Empty;
                if (response.Content != null)
                {
                    body = await response.Content.ReadAsStringAsync();
                }

                throw new InvalidOperationException(
                    $"Expected Status Code 201. Received {(int)response.StatusCode}. Response Body: {body}");
            }
        }

        public async Task<AnnotationSetProperties> GetProperties(string skillId, string annotationId)
        {
            var result = await Client.GetProperties(skillId, annotationId);
            result.AnnotationId = annotationId;
            return result;
        }

        public async Task Delete(string skillId, string annotationId)
        {
            var response = await Client.Delete(skillId, annotationId);

            if (response.StatusCode != HttpStatusCode.NoContent)
            {

                var body = string.Empty;
                if (response.Content != null)
                {
                    body = await response.Content.ReadAsStringAsync();
                }

                throw new InvalidOperationException(
                    $"Expected Status Code 204. Received {(int)response.StatusCode}. Response Body: {body}");
            }
        }

        private async Task<CreateAnnotationSetResponse> Create(string skillId, CreateAnnotationSetRequest request)
        {
            var response = await Client.Create(skillId, request);

            var body = string.Empty;
            if (response.Content != null)
            {
                body = await response.Content.ReadAsStringAsync();
            }

            if (response.StatusCode != HttpStatusCode.Created)
            {
                throw new InvalidOperationException(
                    $"Expected Status Code 201. Received {(int)response.StatusCode}. Response Body: {body}");
            }

            var json = JObject.Parse(body);
            return new CreateAnnotationSetResponse
            {
                Id = json.Value<string>("id"),
                Location = response.Headers.Location
            };
        }
    }
}


text:
UPDATE tournament_player

SET name = $3

WHERE tournament_id = $1 AND id = $2

RETURNING *;

redpajama_set_name: RedPajamaGithub


text:
.. _form_builder:

Form builder
============

The ``wagtailforms`` module allows you to set up single-page forms, such as a 'Contact us' form, as pages of a Wagtail site. It provides a set of base models that site implementers can extend to create their own ``FormPage`` type with their own site-specific templates. Once a page type has been set up in this way, editors can build forms within the usual page editor, consisting of any number of fields. Form submissions are stored for later retrieval through a new 'Forms' section within the Wagtail admin interface; in addition, they can be optionally e-mailed to an address specified by the editor.

Usage
~~~~~

Add ``wagtail.wagtailforms`` to your ``INSTALLED_APPS``:

.. code:: python

    INSTALLED_APPS = [
       ...
       'wagtail.wagtailforms',
    ]

Within the ``models.py`` of one of your apps, create a model that extends ``wagtailforms.models.AbstractEmailForm``:

.. code:: python

    from modelcluster.fields import ParentalKey
    from wagtail.wagtailadmin.edit_handlers import (FieldPanel, InlinePanel,
        MultiFieldPanel)
    from wagtail.wagtailcore.fields import RichTextField
    from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField

    class FormField(AbstractFormField):
        page = ParentalKey('FormPage', related_name='form_fields')

    class FormPage(AbstractEmailForm):
        intro = RichTextField(blank=True)
        thank_you_text = RichTextField(blank=True)

    FormPage.content_panels = [
        FieldPanel('title', classname="full title"),
        FieldPanel('intro', classname="full"),
        InlinePanel('form_fields', label="Form fields"),
        FieldPanel('thank_you_text', classname="full"),
        MultiFieldPanel([
            FieldPanel('to_address', classname="full"),
            FieldPanel('from_address', classname="full"),
            FieldPanel('subject', classname="full"),
        ], "Email")
    ]

``AbstractEmailForm`` defines the fields ``to_address``, ``from_address`` and ``subject``, and expects ``form_fields`` to be defined. Any additional fields are treated as ordinary page content - note that ``FormPage`` is responsible for serving both the form page itself and the landing page after submission, so the model definition should include all necessary content fields for both of those views.

If you do not want your form page type to offer form-to-email functionality, you can inherit from AbstractForm instead of ``AbstractEmailForm``, and omit the ``to_address``, ``from_address`` and ``subject`` fields from the ``content_panels`` definition.

You now need to create two templates named ``form_page.html`` and ``form_page_landing.html`` (where ``form_page`` is the underscore-formatted version of the class name). ``form_page.html`` differs from a standard Wagtail template in that it is passed a variable ``form``, containing a Django ``Form`` object, in addition to the usual ``self`` variable. A very basic template for the form would thus be:

.. code:: html

    {% load wagtailcore_tags %}
    <html>
        <head>
            <title>{{ self.title }}</title>
        </head>
        <body>
            <h1>{{ self.title }}</h1>
            {{ self.intro|richtext }}
            <form action="{% pageurl self %}" method="POST">
                {% csrf_token %}
                {{ form.as_p }}
                <input type="submit">
            </form>
        </body>
    </html>

``form_page_landing.html`` is a regular Wagtail template, displayed after the user makes a successful form submission.


text:
package programminglife.model;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import programminglife.gui.InitFXThread;

import java.util.HashSet;
import java.util.NoSuchElementException;

import static org.junit.Assert.*;

/**
 * The class that handles the tests for the genome graph.
 */
public class GenomeGraphTest {

    private static final String TEST_DB = "test.db";
    private GenomeGraph graph;
    private int nodeID;

    @BeforeClass
    public static void setUpClass() throws Exception {
        InitFXThread.setupClass();
    }

    @Before
    public void setUp() throws Exception {
        graph = new GenomeGraph("test");
        nodeID = 3;
        graph.setSequence(nodeID, "ATCG");

        graph.replaceNode(nodeID);
    }

    @After
    public void tearDown() throws Exception {
        graph.removeCache();
    }

    @Test
    public void getNodeTest() {
        assertTrue(graph.contains(3));
    }

    @Test
    public void getNodeNullTest() {
        assertNull(graph.getChildIDs(121));
    }

    @Test(expected = NoSuchElementException.class)
    public void getNonExistingGenomeTest() {
        graph.getNodeIDs(graph.getGenomeID("nonexistent"));
    }

    @Test
    public void sizeTest() {
        assertEquals(1, graph.size());
        graph.replaceNode(2);
        graph.setSequence(2, "A");
        assertEquals(2, graph.size());
    }

    @Test
    public void containsTest() {
        int node2ID = 2;
        graph.setSequence(2, "ATTCTT");
        graph.replaceNode(node2ID);
        assertTrue(graph.contains(node2ID));

        int node3ID = 37;
        graph.setSequence(37, "AAAAAAAA");
        assertFalse(graph.contains(node3ID));
    }

    @Test
    public void replaceExistingNodeTest() {
        assertEquals("ATCG", graph.getSequence(3));
        graph.setSequence(nodeID, "AAAA");
        graph.replaceNode(nodeID);
        assertEquals("AAAA", graph.getSequence(3));
    }

    @Test
    public void addEdgeTest() {
        graph.replaceNode(42);
        graph.addEdge(3, 42);
        //cacheLastEdges has to be called because else the child relations are not good
        graph.cacheLastEdges();
        assertArrayEquals(new int[]{42}, graph.getChildIDs(3));

    }

    @Test
    public void addMultipleEdgesSameSource() {
        graph.replaceNode(4);
        graph.replaceNode(5);
        graph.addEdge(3, 4);
        graph.addEdge(3, 5);
        assertTrue(graph.contains(4));
        assertTrue(graph.contains(5));

    }

    @Test
    public void addMultipleEdgesDifferentSources() {
        graph.replaceNode(4);
        graph.replaceNode(5);
        graph.addEdge(3, 4);
        graph.addEdge(4, 5);
        assertArrayEquals(new int[]{4}, graph.getChildIDs(3));
        //This should return an empty array because cacheLastEdges is not called yet.
        assertArrayEquals(new int[]{}, graph.getChildIDs(4));
        graph.cacheLastEdges();
        //Now it should return 5.
        assertArrayEquals(new int[]{5}, graph.getChildIDs(4));

    }

    @Test
    public void addAndGetGenomeTest() {
        int[] genomeID = {37};
        graph.setGenomes(3, genomeID);
        assertArrayEquals(genomeID, graph.getGenomes(3));

    }

    @Test
    public void addAndGetMultipleGenomeTest() {
        int[] genomeIDs = {37, 38, 39};
        graph.setGenomes(4, genomeIDs);
        assertArrayEquals(genomeIDs, graph.getGenomes(4));
        assertEquals(3, graph.getGenomes(4).length);
    }

    @Test(expected = NoSuchElementException.class)
    public void getSequenceNotExistingNode() {
        graph.getSequence(4);
    }

    @Test(expected = NoSuchElementException.class)
    public void getSequenceLengthNotExistingNode() {
        graph.getSequenceLength(4);
    }

    @Test
    public void getGenomeNames() {
        graph.addGenome("Genome1");
        graph.addGenome("fasta123");
        HashSet<String> genomes = new HashSet<>();
        genomes.add("Genome1");
        genomes.add("fasta123");
        assertEquals(genomes, graph.getGenomeNames());
        genomes.add("AnotherGenome");
        assertEquals(3, genomes.size());
        assertNotEquals(genomes, graph.getGenomeNames());
    }

    @Test
    public void getGenomeFractionNode() {
        graph.addGenome("Genome1");
        graph.addGenome("Genome2");
        graph.addGenome("Genome3");
        int[] genomeIDs = new int[]{graph.getGenomeID("Genome1"),
                graph.getGenomeID("Genome2")};

        graph.setGenomes(nodeID, genomeIDs);
        assertEquals(0.66666, graph.getGenomeFraction(nodeID), 0.001);
        graph.addGenome("Genome4");
        assertEquals(0.5, graph.getGenomeFraction(nodeID), 0.001);
    }

    @Test(expected = NoSuchElementException.class)
    public void getGenomeNameNoCache() {
        graph.getGenomeName(1231231);
    }

    @Test(expected = NoSuchElementException.class)
    public void getGenomeIDNonExisting() {
        graph.getGenomeID("ThisGenomeDoesNotExist");
    }

    @Test
    public void getGenomeNameCorrect() {
        graph.addGenome("TestGenome");
        graph.addGenome("OtherGenome");
        int testID = graph.getGenomeID("TestGenome");
        int otherID = graph.getGenomeID("OtherGenome");
        assertNotEquals(testID, otherID);

        assertEquals("TestGenome", graph.getGenomeName(testID));
        assertNotEquals("TestGenome", graph.getGenomeName(otherID));

    }

    @Test
    public void getMultipleGenomeNamesCorrect() {
        graph.addGenome("TestGenome");
        graph.addGenome("OtherGenome");
        int testID = graph.getGenomeID("TestGenome");
        int otherID = graph.getGenomeID("OtherGenome");

        HashSet<String> genomeNamesExpected = new HashSet<>();
        genomeNamesExpected.add("TestGenome");
        genomeNamesExpected.add("OtherGenome");
        HashSet<String> actual = new HashSet<>(graph.getGenomeNames(new int[]{testID, otherID}));
        assertEquals(genomeNamesExpected, actual);
    }

    @Test
    public void getMultipleGenomeNamesCorrectCollection() {
        graph.addGenome("TestGenome");
        graph.addGenome("OtherGenome");
        int testID = graph.getGenomeID("TestGenome");
        int otherID = graph.getGenomeID("OtherGenome");

        HashSet<String> genomeNamesExpected = new HashSet<>();
        genomeNamesExpected.add("TestGenome");
        genomeNamesExpected.add("OtherGenome");

        HashSet<Integer> ids = new HashSet<>();
        ids.add(testID);
        ids.add(otherID);
        HashSet<String> actual = new HashSet<>(graph.getGenomeNames(ids));
        assertEquals(genomeNamesExpected,actual);
    }

    @Test
    public void getGenomeNodeIDs() {
        graph.replaceNode(4);
        graph.replaceNode(5);

        int[] genomeIDsA = {37, 55, 89};
        int[] genomeIDsB = {37, 55, 103};
        int[] genomeIDsC = {37, 66, 89};

        graph.setGenomes(3, genomeIDsA);
        graph.setGenomes(4, genomeIDsB);
        graph.setGenomes(5, genomeIDsC);

        HashSet<Integer> expected = new HashSet<>();
        expected.add(3);
        expected.add(4);

        HashSet<Integer> actual = new HashSet<>(graph.getNodeIDs(55));
        assertEquals(expected, actual);

        expected.add(5);
        actual = new HashSet<>(graph.getNodeIDs(37));
        assertEquals(expected, actual);
    }

}


text:
(function () {
  'use strict';

  describe('metadata.service', function () {

    beforeEach(module('horizon.app.core.metadata'));

    var nova = {getAggregateExtraSpecs: function() {},
                getFlavorExtraSpecs: function() {},
                editAggregateExtraSpecs: function() {},
                editFlavorExtraSpecs: function() {},
                getInstanceMetadata: function() {},
                editInstanceMetadata: function() {} };

    var glance = {getImageProps: function() {},
                  editImageProps: function() {},
                  getNamespaces: function() {}};

    beforeEach(function() {
      module(function($provide) {
        $provide.value('horizon.app.core.openstack-service-api.nova', nova);
        $provide.value('horizon.app.core.openstack-service-api.glance', glance);
      });
    });

    var metadataService;

    beforeEach(inject(function($injector) {
      metadataService = $injector.get('horizon.app.core.metadata.service');
    }));

    it('should get aggregate metadata', function() {
      var expected = 'aggregate metadata';
      spyOn(nova, 'getAggregateExtraSpecs').and.returnValue(expected);
      var actual = metadataService.getMetadata('aggregate', '1');
      expect(actual).toBe(expected);
    });

    it('should edit aggregate metadata', function() {
      spyOn(nova, 'editAggregateExtraSpecs');
      metadataService.editMetadata('aggregate', '1', 'updated', ['removed']);
      expect(nova.editAggregateExtraSpecs).toHaveBeenCalledWith('1', 'updated', ['removed']);
    });

    it('should get aggregate namespace', function() {
      spyOn(glance, 'getNamespaces');
      metadataService.getNamespaces('aggregate');
      expect(glance.getNamespaces)
      .toHaveBeenCalledWith({ resource_type: 'OS::Nova::Aggregate' }, false);
    });

    it('should get flavor metadata', function() {
      var expected = 'flavor metadata';
      spyOn(nova, 'getFlavorExtraSpecs').and.returnValue(expected);
      var actual = metadataService.getMetadata('flavor', '1');
      expect(actual).toBe(expected);
    });

    it('should edit flavor metadata', function() {
      spyOn(nova, 'editFlavorExtraSpecs');
      metadataService.editMetadata('flavor', '1', 'updated', ['removed']);
      expect(nova.editFlavorExtraSpecs).toHaveBeenCalledWith('1', 'updated', ['removed']);
    });

    it('should get flavor namespace', function() {
      spyOn(glance, 'getNamespaces');
      metadataService.getNamespaces('flavor');
      expect(glance.getNamespaces)
      .toHaveBeenCalledWith({ resource_type: 'OS::Nova::Flavor' }, false);
    });

    it('should get image metadata', function() {
      var expected = 'image metadata';
      spyOn(glance, 'getImageProps').and.returnValue(expected);
      var actual = metadataService.getMetadata('image', '1');
      expect(actual).toBe(expected);
    });

    it('should edit image metadata', function() {
      spyOn(glance, 'editImageProps');
      metadataService.editMetadata('image', '1', 'updated', ['removed']);
      expect(glance.editImageProps).toHaveBeenCalledWith('1', 'updated', ['removed']);
    });

    it('should get image namespace', function() {
      spyOn(glance, 'getNamespaces');
      metadataService.getNamespaces('image');
      expect(glance.getNamespaces)
      .toHaveBeenCalledWith({ resource_type: 'OS::Glance::Image' }, false);
    });

    it('should get instance metadata', function() {
      var expected = 'instance metadata';
      spyOn(nova, 'getInstanceMetadata').and.returnValue(expected);
      var actual = metadataService.getMetadata('instance', '1');
      expect(actual).toBe(expected);
    });

    it('should edit instance metadata', function() {
      spyOn(nova, 'editInstanceMetadata');
      metadataService.editMetadata('instance', '1', 'updated', ['removed']);
      expect(nova.editInstanceMetadata).toHaveBeenCalledWith('1', 'updated', ['removed']);
    });

    it('should get instance namespace', function() {
      spyOn(glance, 'getNamespaces');
      metadataService.getNamespaces('instance');
      expect(glance.getNamespaces)
      .toHaveBeenCalledWith({ resource_type: 'OS::Nova::Instance' }, false);
    });

  });

})();


text:
<?php

namespace Quartet\Bundle\KakarotBundle\Tests\Service;

use Doctrine\ORM\EntityManager;
use Quartet\Bundle\KakarotBundle\Service\GoogleCalendar;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class GoogleCalendarTest extends WebTestCase
{
    private $em;

    protected function setup()
    {
        $kernel = static::createKernel();
        $kernel->boot();

        $this->em = $kernel->getContainer()->get('doctrine.orm.entity_manager');
    }

    public function testGetYearGoogleCalendar()
    {
        $googleCalendar = new GoogleCalendar($this->em);
        $results = $googleCalendar->getYearGoogleCalendar(date('Y'));

        $this->assertEquals(17, count($results));
    }

    /**
     * @expectedException LogicException
     */
    public function testGetYearGoogleCalendarNull()
    {
        $googleCalendar = new GoogleCalendar($this->em);
        $googleCalendar->getYearGoogleCalendar(null);
    }
}


text:
/*
 * jquery.facetview.js
 *
 * displays faceted browse results by querying a specified elasticsearch index
 * can read config locally or can be passed in as variable when executed
 * or a config variable can point to a remote config
 *
 * created by Mark MacGillivray - mark@cottagelabs.com
 *
 * http://cottagelabs.com
 *
 * There is an explanation of the options below.
 *
 */

var line_chart = null;
var MONTHS = [
    null,
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
];
var dd_width = 850;
var dd_height = 300;

// first define the bind with delay function from (saves loading it separately)
// https://github.com/bgrins/bindWithDelay/blob/master/bindWithDelay.js

(function($) {
    $.fn.bindWithDelay = function( type, data, fn, timeout, throttle ) {
        var wait = null;
        var that = this;

        if ( $.isFunction( data ) ) {
            throttle = timeout;
            timeout = fn;
            fn = data;
            data = undefined;
        }

        function cb() {
            var e = $.extend(true, { }, arguments[0]);
            var throttler = function() {
                wait = null;
                fn.apply(that, [e]);
            };

            if (!throttle) { clearTimeout(wait); }
            if (!throttle || !wait) { wait = setTimeout(throttler, timeout); }
        }

        return this.bind(type, data, cb);
    };
})(jQuery);

// add extension to jQuery with a function to get URL parameters
jQuery.extend({
    getUrlVars: function() {
        var params = new Object;
        var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
        for ( var i = 0; i < hashes.length; i++ ) {
            hash = hashes[i].split('=');
            if ( hash.length > 1 ) {
                if ( hash[1].replace(/%22/gi,"")[0] == "[" || hash[1].replace(/%22/gi,"")[0] == "{" ) {
                    hash[1] = hash[1].replace(/^%22/,"").replace(/%22$/,"");
                    var newval = JSON.parse(unescape(hash[1].replace(/%22/gi,'"')));
                } else {
                    var newval = unescape(hash[1].replace(/%22/gi,'"'));
                }
                params[hash[0]] = newval;
            }
        }
        return params;
    },
    getUrlVar: function(name){
        return jQuery.getUrlVars()[name];
    }
});

// Deal with indexOf issue in <IE9
// provided by commentary in repo issue - https://github.com/okfn/facetview/issues/18
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(searchElement /*, fromIndex */ ) {
        "use strict";
        if (this == null) {
            throw new TypeError();
        }
        var t = Object(this);
        var len = t.length >>> 0;
        if (len === 0) {
            return -1;
        }
        var n = 0;
        if (arguments.length > 1) {
            n = Number(arguments[1]);
            if (n != n) { // shortcut for verifying if it's NaN
                n = 0;
            } else if (n != 0 && n != Infinity && n != -Infinity) {
                n = (n > 0 || -1) * Math.floor(Math.abs(n));
            }
        }
        if (n >= len) {
            return -1;
        }
        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
        for (; k < len; k++) {
            if (k in t && t[k] === searchElement) {
                return k;
            }
        }
        return -1;
    }
}

/* EXPLAINING THE FACETVIEW OPTIONS
Facetview options can be set on instantiation. The list below details which options are available.
Options can also be set and retrieved externally via $.fn.facetview.options.
Query values can also be read from the query parameters of the current page, or provided in
the "source" option for initial search.
Also, whilst facetview is executing a query, it will "show" any element with the "notify-loading" class.
So that class can be applied to any element on a page that can be used to signify loading is taking place.
Once facetview has executed a query, the querystring used is available under "options.querystring".
And the result object as retrieved directly from the index is available under "options.rawdata".
searchbox_class
---------------
This should only be set if embedded_search is set to false, and if an alternative search box on the page should
be used as the source of search terms. If so, this should be set to
the class name (including preceding .) of the text input that should be used as the source of the search terms.
It is only a class instead of an ID so that it can be applied to fields that may already have an ID -
it should really identify a unique box on the page for entering search terms for this instance of facetview.
So an ID could actually also be used - just precede with # instead of .
This makes it possible to embed a search box anywhere on a page and have it be used as the source of simple
search parameters for the facetview. Only the last text box with this clas will be used.
embedded_search
---------------
Default to true, in which case full search term functionality is created and displayed on the page.
If this is false, the search term text box and options will be hidden, so that new search terms cannot
be provided by the user.
It is possible to set an alternative search term input box on the page instead, by setting this to false and
also setting a searchbox_class value to identify the basic source of search terms, in which case such a box
must be manually created elsewhere on the page.
searchbox_shade
---------------
The background colour to apply to the search box
sharesave_link
--------------
Default to true, in which case the searchbox - if drawn by facetview - will be appended with a button that
shows the full current search parameters as a URL.
config_file
-----------
Specify as a URL from which to pull a JSON config file specifying these options.
facets
------
A list of facet objects which should be created as filter options on the page.
As per elasticsearch facets settings, plus "display" as a display name for the facet, instead of field name.
If these should be nested, define them with full scope e.g. nestedobj.nestedfield.
extra_facets
------------
An object of named extra facet objects that should be submitted and executed on each query.
These will NOT be used to generate filters on the page, but the result object can be queried
for their content for other purposes.
searchbox_fieldselect
---------------------
A list of objects specifying fields to which search terms should be restricted.
Each object should have a "display" value for displaying as the name of the option,
and a "field" option specifying the field to restrict the search to.
search_sortby
----------------
A list of objects describing sort option dropdowns.
Each object requires a "display" value, and "field" value upon which to sort results.
NOTE sort fields must be unique on the ES index, NOT lists. Otherwise it will fail silently. Choose wisely.
enable_rangeselect
------------------
RANGES NEED SOME WORK AFTER RECENT UPDATE, KEEP DISABLED FOR NOW
Enable or disable the ability to select a range of filter values
include_facets_in_querystring
-----------------------------
Default to false.
Whether or not to include full facet settings in the querystring when it is requested for display.
This makes it easier to get the querystring for other purposes, but does not change the query that is
sent to the index.
result_display
--------------
A display template for search results. It is a list of lists.
Each list specifies a line. Within each list, specify the contents of the line using objects to describe
them. Each content piece should pertain to a particular "field" of the result set, and should specify what
to show "pre" and "post" the given field
display_images
--------------
Default to true, in which case any image found in a given result object will be displayed to the left
in the result object output.
description
-----------
Just an option to provide a human-friendly description of the functionality of the instantiated facetview.
Like "search my shop". Will be displayed on the page.
search_url
----------
The URL at the index to which searches should be submitted in order to retrieve JSON results.
datatype
--------
The datatype that should be used when submitting a search to the index - e.g. JSON for local, JSONP for remote.
initialsearch
-------------
Default to true, in which case a search-all will be submitted to the index on page load.
Set to false to wait for user input before issuing the first search.
fields
------
A list of which fields the index should return in result objects (by default elasticsearch returns them all).
partial_fields
--------------
A definition of which fields to return, as per elasticsearch docs http://www.elasticsearch.org/guide/reference/api/search/fields.html
nested
------
A list of keys for which the content should be considered nested for query and facet purposes.
NOTE this requires that such keys be referenced with their full scope e.g. nestedobj.nestedfield.
Only works on top-level keys so far.
default_url_params
------------------
Any query parameters that the index search URL needs by default.
freetext_submit_delay
---------------------
When search terms are typed in the search box, they are automatically submitted to the index.
This field specifies in milliseconds how long to wait before sending another query - e.g. waiting
for the user to finish typing a word.
q
-
Specify a query value to start with when the page is loaded. Will be submitted as the initial search value
if initialsearch is enabled. Will also be set as the value of the searchbox on page load.
predefined_filters
------------------
Facet / query values to apply to all searches. Give each one a reference key, then in each object define it
as per an elasticsearch query for appending to the bool must.
If these filters should be applied at the nested level, then prefix the name with the relevant nesting prefix.
e.g. if the nested object is called stats, call the filter stats.MYFILTER.
filter
-------
JSON document describing an `elasticsearch filter <http://www.elasticsearch.org/guide/reference/api/search/filter/>`_
paging
------
An object defining the paging settings:
    from
    ----
    Which result number to start displaying results from
    size
    ----
    How many results to get and display per "page" of results
pager_on_top
------------
Default to false, in which case the pager - e.g. result count and prev / next page buttons - only appear
at the bottom of the search results.
Set to true to show the pager at the top of the search results as well.
pager_slider
------------
If this is set to true, then the paging options will be a left and right arrow at the bottom, with the
count in between, but a bit bigger and more slider-y than the standard one. Works well for displaying
featured content, for example.
sort
----
A list of objects defining how to sort the results, as per elasticsearch sorting.
searchwrap_start
searchwrap_end
----------------
HTML values in which to wrap the full result set, to style them into the page they are being injected into.
resultwrap_start
resultwrap_end
----------------
HTML values in which to wrap each result object
result_box_colours
------------------
A list of background colours that will be randomly assigned to each result object that has the "result_box"
class. To use this, specify the colours in this list and ensure that the "result_display" option uses the
"result_box" class to wrap the result objects.
fadein
------
Define a fade-in delay in milliseconds so that whenever a new list of results is displays, it uses the fade-in effect.
post_search_callback
--------------------
This can define or reference a function that will be executed any time new search results are retrieved and presented on the page.
pushstate
---------
Updates the URL string with the current query when the user changes the search terms
linkify
-------
Makes any URLs in the result contents into clickable links
default_operator
----------------
Sets the default operator in text search strings - elasticsearch uses OR by default, but can also be AND
default_freetext_fuzzify
------------------------
If this exists and is not false, it should be either * or ~. If it is * then * will be prepended and appended
to each string in the freetext search term, and if it is ~ then ~ will be appended to each string in the freetext
search term. If * or ~ or : are already in the freetext search term, it will be assumed the user is already trying
to do a complex search term so no action will be taken. NOTE these changes are not replicated into the freetext
search box - the end user will not know they are happening.
*/

// now the facetview function
(function($){
    $.fn.facetview = function(options) {

        // a big default value (pulled into options below)
        // demonstrates how to specify an output style based on the fields that can be found in the result object
        // where a specified field is not found, the pre and post for it are just ignored
         var resdisplay = [
                [
                    {
                        "field": "author.name"
                    },
                    {
                        "pre": "(",
                        "field": "year",
                        "post": ")"
                    }
                ],
                [
                    {
                        "pre": "",
                        "field": "title",
                        "alternative_field": "booktitle",
                        "post": ""
                    }
                ],
                [
                    {
                        "field": "howpublished"
                    },
                    {
                        "pre": "in ",
                        "field": "journal.name",
                        "post": ","
                    },
                    {
                        "pre": "",
                        "field": "booktitle",
                        "post": ","
                    },
                    {
                        "pre": "vol. ",
                        "field": "volume",
                        "post": ","
                    },
                    {
                        "pre": "p. ",
                        "field": "pages"
                    },
                    {
                        "field": "publisher"
                    }
                ],
                [
                    {
                        "field": "link.url"
                    }
                ],
                [
                    {
                        "pre": "",
                        "highlight_field": "text",
                        "post": ""
                    }
                ]
            ];

        // specify the defaults
        var defaults = {
            "config_file": false,
            "embedded_search": true,
            "searchbox_class": "",
            "searchbox_fieldselect": [],
            "searchbox_shade": "#ecf4ff",
            "search_sortby": [],
            "sharesave_link": true,
            "description":"",
            "facets":[],
            "default_url_params":{
            'facet.mincount':1,
            'wt':'json',
            'indent':'true'
            },
            "solr_paging_params":{
                "from":"start",
                "size":"rows"
            },
            "query_parameter":"q",
            "extra_facets": {},
            "enable_rangeselect": false,
            "include_facets_in_querystring": false,
            "result_display": resdisplay,
            "display_images": true,
            "search_url":"",
            "datatype":"jsonp",
            "initialsearch":true,
            "fields": false,
            "partial_fields": false,
            "nested": [],
            "default_url_params":{},
            "freetext_submit_delay":"500",
            "q":"",
            "sort":[],
            "predefined_filters":{},
            "paging":{
                "from":0,
                "size":10
            },
            "pager_on_top": false,
            "pager_slider": false,
            "searchwrap_start":'
',
            "searchwrap_end":"
",
            "resultwrap_start":"
",
            "resultwrap_end":"
",
            "result_box_colours":[],
            "fadein":800,
            "post_search_callback": false,
            "pushstate": true,
            "linkify": true,
            "default_operator": "OR",
            "default_freetext_fuzzify": false
        };

        // and add in any overrides from the call
        // these options are also overridable by URL parameters
        // facetview options are declared as a function so they are available externally
        // (see bottom of this file)
        var provided_options = $.extend(defaults, options);
        var url_options = $.getUrlVars();
        $.fn.facetview.options = $.extend(provided_options,url_options);
        var options = $.fn.facetview.options;

        // ===============================================
        // functions to do with filters
        // ===============================================

        // show the filter values
        var showfiltervals = function(event) {
            event.preventDefault();
            if ( $(this).hasClass('facetview_open') ) {
                $(this).children('i').removeClass('icon-minus');
                $(this).children('i').addClass('icon-plus');
                $(this).removeClass('facetview_open');
                $('[id="facetview_' + $(this).attr('rel') +'"]', obj ).children().find('.facetview_filtervalue').hide();
                $(this).siblings('.facetview_filteroptions').hide();
            } else {
                $(this).children('i').removeClass('icon-plus');
                $(this).children('i').addClass('icon-minus');
                $(this).addClass('facetview_open');
                $('[id="facetview_' + $(this).attr('rel') +'"]', obj ).children().find('.facetview_filtervalue').show();
                $(this).siblings('.facetview_filteroptions').show();
            }
        };

        // function to switch filters to OR instead of AND
        var orfilters = function(event) {
            event.preventDefault();
            if ( $(this).attr('rel') == 'AND' ) {
                $(this).attr('rel','OR');
                $(this).css({'color':'#333'});
                $('.facetview_filterselected[rel="' + $(this).attr('href') + '"]', obj).addClass('facetview_logic_or');
            } else {
                $(this).attr('rel','AND');
                $(this).css({'color':'#aaa'});
                $('.facetview_filterselected[rel="' + $(this).attr('href') + '"]', obj).removeClass('facetview_logic_or');
            }
            dosearch();
        }

        // function to perform for sorting of filters
        var sortfilters = function(event) {
            event.preventDefault();
            var sortwhat = $(this).attr('href');
            var which = 0;
            for ( var i = 0; i < options.facets.length; i++ ) {
                var item = options.facets[i];
                if ('field' in item) {
                    if ( item['field'] == sortwhat) {
                        which = i;
                    }
                }
            }
            // iterate to next sort type on click. order is term, rterm, count, rcount
            if ( $(this).hasClass('facetview_term') ) {
                options.facets[which]['order'] = 'reverse_term';
                $(this).html('a-z ');
                $(this).removeClass('facetview_term').addClass('facetview_rterm');
            } else if ( $(this).hasClass('facetview_rterm') ) {
                options.facets[which]['order'] = 'count';
                $(this).html('count ');
                $(this).removeClass('facetview_rterm').addClass('facetview_count');
            } else if ( $(this).hasClass('facetview_count') ) {
                options.facets[which]['order'] = 'reverse_count';
                $(this).html('count ');
                $(this).removeClass('facetview_count').addClass('facetview_rcount');
            } else if ( $(this).hasClass('facetview_rcount') ) {
                options.facets[which]['order'] = 'term';
                $(this).html('a-z ');
                $(this).removeClass('facetview_rcount').addClass('facetview_term');
            }
            dosearch();
        };

        // adjust how many results are shown
        var morefacetvals = function(event) {
            event.preventDefault();
            var morewhat = options.facets[ $(this).attr('rel') ];
            if ('size' in morewhat ) {
                var currentval = morewhat['size'];
            } else {
                var currentval = 10;
            }
            var newmore = prompt('Currently showing ' + currentval + '. How many would you like instead?');
            if (newmore) {
                options.facets[ $(this).attr('rel') ]['size'] = parseInt(newmore);
                $(this).html(newmore);
                dosearch();
            }
        };

        // insert a facet range once selected
        // TODO: UPDATE
        var dofacetrange = function(rel) {
            $('#facetview_rangeresults_' + rel, obj).remove();
            var range = $('#facetview_rangechoices_' + rel, obj).html();
            var newobj = '
 \
                ' +
                range + '
';
            $('#facetview_selectedfilters', obj).append(newobj);
            $('.facetview_filterselected', obj).unbind('click',clearfilter);
            $('.facetview_filterselected', obj).bind('click',clearfilter);
            options.paging.from = 0;
            dosearch();
        };
        // clear a facet range
        var clearfacetrange = function(event) {
            event.preventDefault();
            $('#facetview_rangeresults_' + $(this).attr('rel'), obj).remove();
            $('#facetview_rangeplaceholder_' + $(this).attr('rel'), obj).remove();
            dosearch();
        };
        // build a facet range selector
        var facetrange = function(event) {
            // TODO: when a facet range is requested, should hide the facet list from the menu
            // should perhaps also remove any selections already made on that facet
            event.preventDefault();
            var rel = $(this).attr('rel');
            var rangeselect = '
 \

 \

 \
                ... \
                to \
                ...
 \

';
            rangeselect += ' \

 \

 \

';
            $('#facetview_selectedfilters', obj).after(rangeselect);
            $('.facetview_facetrange_remove', obj).unbind('click',clearfacetrange);
            $('.facetview_facetrange_remove', obj).bind('click',clearfacetrange);
            var values = [];
            var valsobj = $( '#facetview_' + $(this).attr('href').replace(/\./gi,'_'), obj );
            valsobj.find('.facetview_filterchoice', obj).each(function() {
                values.push( $(this).attr('href') );
            });
            values = values.sort();
            $( "#facetview_slider_" + rel, obj ).slider({
                range: true,
                min: 0,
                max: values.length-1,
                values: [0,values.length-1],
                slide: function( event, ui ) {
                    $('#facetview_rangechoices_' + rel + ' .facetview_lowrangeval_' + rel, obj).html( values[ ui.values[0] ] );
                    $('#facetview_rangechoices_' + rel + ' .facetview_highrangeval_' + rel, obj).html( values[ ui.values[1] ] );
                    dofacetrange( rel );
                }
            });
            $('#facetview_rangechoices_' + rel + ' .facetview_lowrangeval_' + rel, obj).html( values[0] );
            $('#facetview_rangechoices_' + rel + ' .facetview_highrangeval_' + rel, obj).html( values[ values.length-1] );
        };

        // pass a list of filters to be displayed
        var buildfilters = function() {
            if ( options.facets.length > 0 ) {
                var filters = options.facets;
                var thefilters = '';
                for ( var idx = 0; idx < filters.length; idx++ ) {
                    var _filterTmpl = '
 \

 {{FILTER_DISPLAY}} \
                         \

 \
                            ? \
                            {{FILTER_HOWMANY}} \
                            {{FILTER_SORTCONTENT}} \
                            OR \
                            ';
                    if ( options.enable_rangeselect ) {
                        _filterTmpl += 'range';
                    }
                    _filterTmpl +='
 \

 \

';
                    _filterTmpl = _filterTmpl.replace(/{{FILTER_NAME}}/g, filters[idx]['field'].replace(/\./gi,'_').replace(/\:/gi,'_')).replace(/{{FILTER_EXACT}}/g, filters[idx]['field']);
                    thefilters += _filterTmpl;
                    if ('size' in filters[idx] ) {
                        thefilters = thefilters.replace(/{{FILTER_HOWMANY}}/gi, filters[idx]['size']);
                    } else {
                        thefilters = thefilters.replace(/{{FILTER_HOWMANY}}/gi, 10);
                    };
                    if ( 'order' in filters[idx] ) {
                        if ( filters[idx]['order'] == 'term' ) {
                            thefilters = thefilters.replace(/{{FILTER_SORTTERM}}/g, 'facetview_term');
                            thefilters = thefilters.replace(/{{FILTER_SORTCONTENT}}/g, 'a-z ');
                        } else if ( filters[idx]['order'] == 'reverse_term' ) {
                            thefilters = thefilters.replace(/{{FILTER_SORTTERM}}/g, 'facetview_rterm');
                            thefilters = thefilters.replace(/{{FILTER_SORTCONTENT}}/g, 'a-z ');
                        } else if ( filters[idx]['order'] == 'count' ) {
                            thefilters = thefilters.replace(/{{FILTER_SORTTERM}}/g, 'facetview_count');
                            thefilters = thefilters.replace(/{{FILTER_SORTCONTENT}}/g, 'count ');
                        } else if ( filters[idx]['order'] == 'reverse_count' ) {
                            thefilters = thefilters.replace(/{{FILTER_SORTTERM}}/g, 'facetview_rcount');
                            thefilters = thefilters.replace(/{{FILTER_SORTCONTENT}}/g, 'count ');
                        };
                    } else {
                        thefilters = thefilters.replace(/{{FILTER_SORTTERM}}/g, 'facetview_count');
                        thefilters = thefilters.replace(/{{FILTER_SORTCONTENT}}/g, 'count ');
                    };
                    thefilters = thefilters.replace(/{{FACET_IDX}}/gi,idx);
                    if ('display' in filters[idx]) {
                        thefilters = thefilters.replace(/{{FILTER_DISPLAY}}/g, filters[idx]['display']);
                    } else {
                        thefilters = thefilters.replace(/{{FILTER_DISPLAY}}/g, filters[idx]['field']);
                    };
                };
                $('#facetview_filters', obj).html("").append(thefilters);
                $('.facetview_morefacetvals', obj).bind('click',morefacetvals);
                $('.facetview_facetrange', obj).bind('click',facetrange);
                $('.facetview_sort', obj).bind('click',sortfilters);
                $('.facetview_or', obj).bind('click',orfilters);
                $('.facetview_filtershow', obj).bind('click',showfiltervals);
                $('.facetview_learnmore', obj).unbind('click',learnmore);
                $('.facetview_learnmore', obj).bind('click',learnmore);
                options.description ? $('#facetview_filters', obj).append('
' + options.description + '
') : "";
            };
        };

        // trigger a search when a filter choice is clicked
        // or when a source param is found and passed on page load
        var clickfilterchoice = function(event,rel,href) {
            if ( event ) {
                event.preventDefault();
                var rel = $(this).attr("rel");
                var href = $(this).attr("href");
            }
            var relclean = rel.replace(/\./gi,'_').replace(/\:/gi,'_');
            // Do nothing if element already exists.
            if( $('a.facetview_filterselected[href="'+href+'"][rel="'+rel+'"]').length ){
                return null;
            }

            var newobj = '' +
                href + ' ';

            if ( $('#facetview_group_' + relclean, obj).length ) {
                $('#facetview_group_' + relclean, obj).append(newobj);
            } else {
                var pobj = '
';
                pobj += newobj + '
';
                $('#facetview_selectedfilters', obj).append(pobj);
            };

            $('.facetview_filterselected', obj).unbind('click',clearfilter);
            $('.facetview_filterselected', obj).bind('click',clearfilter);
            if ( event ) {
                options.paging.from = 0;
                dosearch();
            };
        };

        // clear a filter when clear button is pressed, and re-do the search
        var clearfilter = function(event) {
            event.preventDefault();
            if ( $(this).siblings().length == 0 ) {
                $(this).parent().remove();
            } else {
                $(this).remove();
            }
            dosearch();
        };

        // ===============================================
        // functions to do with building results
        // ===============================================

        // read the result object and return useful vals
        // returns an object that contains things like ["data"] and ["facets"]
        var parseresults = function(dataobj) {
            var resultobj = new Object();
            resultobj["records"] = new Array();
            resultobj["start"] = "";
            resultobj["found"] = "";
            resultobj["facets"] = new Object();
            if (options.search_index == "elasticsearch"){
                for ( var item = 0; item < dataobj.hits.hits.length; item++ ) {
                    if ( options.fields ) {
                        resultobj["records"].push(dataobj.hits.hits[item].fields);
                    } else if ( options.partial_fields ) {
                        var keys = [];
                        for(var key in options.partial_fields){
                            keys.push(key);
                        }
                        resultobj["records"].push(dataobj.hits.hits[item].fields[keys[0]]);
                    } else {
                        resultobj["records"].push(dataobj.hits.hits[item]._source);
                    }
                }
                resultobj["start"] = "";
                resultobj["found"] = dataobj.hits.total;
                for (var item in dataobj.facets) {
                    var facetsobj = new Object();
                    for (var thing = 0; thing < dataobj.facets[item]["terms"].length; thing++) {
                        facetsobj[ dataobj.facets[item]["terms"][thing]["term"] ] = dataobj.facets[item]["terms"][thing]["count"];
                    }
                    resultobj["facets"][item] = facetsobj;
                }
            }
            else{
                resultobj["records"] = dataobj.response.docs;
                resultobj["start"] = dataobj.response.start;
                resultobj["found"] = dataobj.response.numFound;
                if (dataobj.facet_counts) {
                    for (var item in dataobj.facet_counts.facet_fields) {
                        var facetsobj = new Object();
                        var count = 0;
                        for ( var each in dataobj.facet_counts.facet_fields[item]) {
                            if ( count % 2 == 0 ) {
                            facetsobj[ dataobj.facet_counts.facet_fields[item][each] ] = dataobj.facet_counts.facet_fields[item][count + 1];
                            }
                            count += 1;
                        }
                        resultobj["facets"][item] = facetsobj;
                    }
                }
            }
            return resultobj;
        };

        // decrement result set
        var decrement = function(event) {
            event.preventDefault();
            if ( $(this).html() != '..' ) {
                options.paging.from = options.paging.from - options.paging.size;
                options.paging.from < 0 ? options.paging.from = 0 : "";
                dosearch();
            }
        };
        // increment result set
        var increment = function(event) {
            event.preventDefault();
            if ( $(this).html() != '..' ) {
                options.paging.from = parseInt($(this).attr('href'));
                dosearch();
            }
        };

        // used to get value by dotted notation in result_display
        var getvalue = function(obj, dotted_notation) {
            if(!dotted_notation) return;
            var parts = dotted_notation.split('.');
            parts.reverse();
            var ref = [parts.pop()];
            while (parts.length && !(ref.join(".") in obj)) {
                ref.push(parts.pop());
            }
            var addressed_ob = obj[ref.join(".")];
            var left = parts.reverse().join(".");

            if (addressed_ob && addressed_ob.constructor.toString().indexOf("Array") == -1) {
                if (parts.length)
                    return getvalue(addressed_ob, left);
                else
                    return addressed_ob;
            } else {
                if ( addressed_ob !== undefined ) {
                    var thevalue = [];
                    for ( var row = 0; row < addressed_ob.length; row++ ) {
                        thevalue.push(addressed_ob[row]);
                    }
                    return thevalue;
                } else {
                    return undefined;
                }
            }
        };

        // given a result record, build how it should look on the page
        var buildrecord = function(index) {
            var record = options.data['records'][index];
            var result = options.resultwrap_start;
            // add first image where available
            if (options.display_images) {

                // TODO: this is where we need to take the URL as stored in ID field, translate it to a web URL, and show it.

                var recstr = JSON.stringify(record);
                var regex = /(http:\/\/\S+?\.(jpg|png|gif|jpeg))/;
                var img = regex.exec(recstr);
                if (img) {
                    result += '';
                }
            }
            // add the record based on display template if available
            var display = options.result_display;
            var lines = '';
            for ( var lineitem = 0; lineitem < display.length; lineitem++ ) {
                line = "";
                for ( var object = 0; object < display[lineitem].length; object++ ) {
                    var thekey = display[lineitem][object]['field'];
                    var thevalue = getvalue(record, thekey);
                    if (thevalue && thevalue.toString().length) {
                            line += display[lineitem][object]['pre'] ? display[lineitem][object]['pre'] : false;
                        if ( typeof(thevalue) == 'object' ) {
                            for ( var val = 0; val < thevalue.length; val++ ) {
                                line += val != 0 ? ', ' : false;
                                line += thevalue[val];
                            }
                        } else {
                            line += thevalue;
                        }
                        display[lineitem][object]['post']
                            ? line += display[lineitem][object]['post'] : line += ' ';
                    }
                }
                if (line) {
                    lines += line.replace(/^\s/,'').replace(/\s$/,'').replace(/\,$/,'') + "
";
                }
            }
            lines ? result += lines : result += JSON.stringify(record,"","    ");
            result += options.resultwrap_end;
            return result;
        };

        // view a full record when selected
        var viewrecord = function(event) {
            event.preventDefault();
            var record = options.data['records'][$(this).attr('href')];
            alert(JSON.stringify(record,"","    "));

        }

        // put the results on the page
        var showresults = function(sdata) {
            options.rawdata = sdata;
            // get the data and parse from the es layout
            var data = parseresults(sdata);
            options.data = data;

            // initialize plot
            if (line_chart == null && options.linechart_field != null && options.linechart_field != "") {
                line_chart = c3.generate({
                    bindto: '#line_chart',
                    data: {
                        x: 'year',
                        columns: [
                        ]
                    }
                });
            }

            // for each filter setup, find the results for it and append them to the relevant filter
            for ( var each = 0; each < options.facets.length; each++ ) {
                var facet = options.facets[each]['field'];
                var facetclean = options.facets[each]['field'].replace(/\./gi,'_').replace(/\:/gi,'_');
                var facet_filter = $('[id="facetview_'+facetclean+'"]', obj);
                facet_filter.children().find('.facetview_filtervalue').remove();
                var records = data["facets"][ facet ];

                // compensate for Solr not being able to show facet results in reverse order
                if ("order" in options.facets[each] && options.facets[each]["order"].indexOf("reverse") > -1) {
                    // http://stackoverflow.com/questions/18977881/can-i-loop-through-a-javascript-object-in-reverse-order
                    function ReverseObject(Obj){
                        var TempArr = [];
                        var NewObj = {};
                        for (var Key in Obj){
                            TempArr.push(Key);
                        }
                        for (var i = TempArr.length-1; i >= 0; i--){
                            NewObj[TempArr[i]] = Obj[TempArr[i]];
                        }
                        return NewObj;
                    };
                    records = ReverseObject(records);
                }

        var years = ['year'];
                var year_hits = ['hits'];
        var lineChartFacet = false;
        var dendrogramFacet = false;
        if (facet == options.linechart_field){
            lineChartFacet = true;
        }

        if (facet == options.dendrogram_field){
            dendrogramFacet = true;
        }

        for ( var item in records ) {
            var append = '
' + item +
                ' (' + records[item] + ')
';
            facet_filter.append(append);

            if (lineChartFacet){
                years.push(item);
                year_hits.push(records[item]);
            }

            }

            if ( $('.facetview_filtershow[rel="' + facetclean + '"]', obj).hasClass('facetview_open') ) {
                facet_filter.children().find('.facetview_filtervalue').show();
            }

        if(lineChartFacet){
            // clean the years and hits
            var year_hash = {}
            for (var i = 0; i < years.length; i++){
                if (years[i] == "year") continue;
                var year = years[i].substring(0,4);
                if (year in year_hash){
                    hits = parseInt(years[year]);
                    hits += parseInt(year_hits[i]);
                }
                            else{
                                year_hash[year] = year_hits[i];
                }
            }

            years = [];
            year_hits = [];
            years.push('year');
            year_hits.push('hits');
            for (var year in year_hash){
            years.push(year);
            year_hits.push(year_hash[year]);
            }

            line_chart.load({
            columns: [
                years,
                year_hits
                ]
            });
        }

        if (dendrogramFacet){
                      $('#dendrogram').empty();
                      dendrogram = null;
                      var facet_selected = $('a.facetview_filterselected[rel="'+facet+'"]');
                      var root = {};
                      if (facet_selected.length > 0) {
                          dd_cluster = d3.layout.cluster().size([dd_height, dd_width - 160]);
                          dd_diagonal = d3.svg.diagonal().projection(function(d) { return [d.y, d.x]; });
                          dendrogram = d3.select("#dendrogram").append("svg:svg")
                                         .attr("width", dd_width)
                                         .attr("height", dd_height)
                                         .append("svg:g")
                                         .attr("transform", "translate(80, 0)");
                          var facet_text = facet_selected[0].text;
                          //alert(facet_text);
                          root = {
                              "name": facet_text,
                              "children": []
                          };
                          //alert(data.records);
                          var rel_nodes = [];
                          for ( var i = 0; i < data.records.length; i++ ) {
                                var drec = data.records[i];
                                var drec_length = 0;
                                var drec_facet = eval('drec.'+facet);
                                if (drec_facet != undefined){
                                    drec_length = drec_facet.length;
                                }
                                for (var j = 0; j < drec_length; j++) {
                                    var rel_node = eval('drec.'+facet+'[j]');
                                    if (facet_text.toLowerCase().trim() != rel_node.toLowerCase().trim() && rel_nodes.indexOf(rel_node) == -1) {
                                        root.children.push({ "name": rel_node, "children": []});
                                        rel_nodes.push(rel_node);
                                        }
                                    }
                            }

                          var nodes = dd_cluster.nodes(root),
                              links = dd_cluster.links(nodes);

                          var link = dendrogram.selectAll(".link")
                              .data(links)
                            .enter().append("path")
                              .attr("class", "link")
                              .attr("d", dd_diagonal);

                          var node = dendrogram.selectAll(".node")
                              .data(nodes)
                            .enter().append("g")
                              .attr("class", "node")
                              .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

                          node.append("circle")
                              .attr("r", 4.5);

                          node.append("text")
                              .attr("dx", function(d) { return d.children ? -8 : 8; })
                              .attr("dy", 3)
                              .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
                              .text(function(d) { return d.name; });

                        d3.select(self.frameElement).style("height", dd_height + "px");

             }

        }

            }
            $('.facetview_filterchoice', obj).bind('click',clickfilterchoice);
            $('.facetview_filters', obj).each(function() {
                $(this).find('.facetview_filtershow').css({'color':'#333','font-weight':'bold'}).children('i').show();
                if ( $(this).children().find('.facetview_filtervalue').length > 1 ) {
                    $(this).show();
                } else {
                    //$(this).hide();
                    $(this).find('.facetview_filtershow').css({'color':'#ccc','font-weight':'normal'}).children('i').hide();
                };
            });

            // put result metadata on the page
            if ( typeof(options.paging.from) != 'number' ) {
                options.paging.from = parseInt(options.paging.from);
            }
            if ( typeof(options.paging.size) != 'number' ) {
                options.paging.size = parseInt(options.paging.size);
            }
            if ( options.pager_slider ) {
                var metaTmpl = '
 \
                    < \
                    {{from}} – {{to}} of {{total}} \
                    > \

';
            } else {
                var metaTmpl = '
 \

 \

« back
 \

{{from}} – {{to}} of {{total}}
 \

next »
 \

 \

';
            };
            $('.facetview_metadata', obj).first().html("Not found...");
            if (data.found) {
                var from = options.paging.from + 1;
                var size = options.paging.size;
                !size ? size = 100 : "";
                var to = options.paging.from+size;
                data.found < to ? to = data.found : "";
                var meta = metaTmpl.replace(/{{from}}/g, from);
                meta = meta.replace(/{{to}}/g, to);
                meta = meta.replace(/{{total}}/g, data.found);
                $('.facetview_metadata', obj).html("").append(meta);
                $('.facetview_decrement', obj).bind('click',decrement);
                from < size ? $('.facetview_decrement', obj).html('..') : "";
                $('.facetview_increment', obj).bind('click',increment);
                data.found <= to ? $('.facetview_increment', obj).html('..') : "";
            }

            // put the filtered results on the page
            $('#facetview_results',obj).html("");
            var infofiltervals = new Array();

            $.each(data.records, function(index, value) {
                // write them out to the results div
                 $('#facetview_results', obj).append( buildrecord(index) );
                 options.linkify ? $('#facetview_results tr:last-child', obj).linkify() : false;
            });
            if ( options.result_box_colours.length > 0 ) {
                jQuery('.result_box', obj).each(function () {
                    var colour = options.result_box_colours[Math.floor(Math.random()*options.result_box_colours.length)] ;
                    jQuery(this).css("background-color", colour);
                });
            }
            $('#facetview_results', obj).children().hide().fadeIn(options.fadein);
            $('.facetview_viewrecord', obj).bind('click',viewrecord);
            jQuery('.notify_loading').hide();
            // if a post search callback is provided, run it
            if (typeof options.post_search_callback == 'function') {
                options.post_search_callback.call(this);
            }
        };

        // ===============================================
        // functions to do with searching
        // ===============================================

        // fuzzify the freetext search query terms if required
        var fuzzify = function(querystr) {
            var rqs = querystr
            if ( options.default_freetext_fuzzify !== undefined ) {
                if ( options.default_freetext_fuzzify == "*" || options.default_freetext_fuzzify == "~" ) {
                    if ( querystr.indexOf('*') == -1 && querystr.indexOf('~') == -1 && querystr.indexOf(':') == -1 ) {
                        var optparts = querystr.split(' ');
                        pq = "";
                        for ( var oi = 0; oi < optparts.length; oi++ ) {
                            var oip = optparts[oi];
                            if ( oip.length > 0 ) {
                                oip = oip + options.default_freetext_fuzzify;
                                options.default_freetext_fuzzify == "*" ? oip = "*" + oip : false;
                                pq += oip + " ";
                            }
                        };
                        rqs = pq;
                    };

                };
            };
            return rqs;
        };

        // build the search query URL based on current params
        var elasticsearchquery = function() {
            var qs = {};
            var bool = false;
            var nested = false;
            var seenor = []; // track when an or group are found and processed
            $('.facetview_filterselected',obj).each(function() {
                !bool ? bool = {'must': [] } : "";
                if ( $(this).hasClass('facetview_facetrange') ) {
                    var rngs = {
                        'from': $('.facetview_lowrangeval_' + $(this).attr('rel'), this).html(),
                        'to': $('.facetview_highrangeval_' + $(this).attr('rel'), this).html()
                    };
                    var rel = options.facets[ $(this).attr('rel') ]['field'];
                    var robj = {'range': {}};
                    robj['range'][ rel ] = rngs;
                    // check if this should be a nested query
                    var parts = rel.split('.');
                    if ( options.nested.indexOf(parts[0]) != -1 ) {
                        !nested ? nested = {"nested":{"_scope":parts[0],"path":parts[0],"query":{"bool":{"must":[robj]}}}} : nested.nested.query.bool.must.push(robj);
                    } else {
                        bool['must'].push(robj);
                    }
                } else {
                    // TODO: check if this has class facetview_logic_or
                    // if so, need to build a should around it and its siblings
                    if ( $(this).hasClass('facetview_logic_or') ) {
                        if ( !($(this).attr('rel') in seenor) ) {
                            seenor.push($(this).attr('rel'));
                            var bobj = {'bool':{'should':[]}};
                            $('.facetview_filterselected[rel="' + $(this).attr('rel') + '"]').each(function() {
                                if ( $(this).hasClass('facetview_logic_or') ) {
                                    var ob = {'term':{}};
                                    ob['term'][ $(this).attr('rel') ] = $(this).attr('href');
                                    bobj.bool.should.push(ob);
                                };
                            });
                            if ( bobj.bool.should.length == 1 ) {
                                var spacer = {'match_all':{}};
                                bobj.bool.should.push(spacer);
                            }
                        }
                    } else {
                        var rel = $(this).attr('rel');
                        var facet = options.facets.filter(function(f) {
                            return f['field'] === rel && f['facet_filter'];
                        })[0];
                        var bobj = {'term':{}};
                        bobj['term'][rel] = $(this).attr('href');
                        if (facet) {
                            qs['filter'] = facet['facet_filter'];
                        }
                    }

                    // check if this should be a nested query
                    var parts = $(this).attr('rel').split('.');
                    if ( options.nested.indexOf(parts[0]) != -1 ) {
                        !nested ? nested = {"nested":{"_scope":parts[0],"path":parts[0],"query":{"bool":{"must":[bobj]}}}} : nested.nested.query.bool.must.push(bobj);
                    } else {
                        bool['must'].push(bobj);
                    }
                }
            });
            for (var item in options.predefined_filters) {
                !bool ? bool = {'must': [] } : "";
                var pobj = options.predefined_filters[item];
                var parts = item.split('.');
                if ( options.nested.indexOf(parts[0]) != -1 ) {
                    !nested ? nested = {"nested":{"_scope":parts[0],"path":parts[0],"query":{"bool":{"must":[pobj]}}}} : nested.nested.query.bool.must.push(pobj);
                } else {
                    bool['must'].push(pobj);
                }
            }
            if (bool) {
                if ( options.q != "" ) {
                    var qryval = { 'query': fuzzify(options.q) };
                    $('.facetview_searchfield', obj).val() != "" ? qryval.default_field = $('.facetview_searchfield', obj).val() : "";
                    options.default_operator !== undefined ? qryval.default_operator = options.default_operator : false;
                    bool['must'].push( {'query_string': qryval } );
                };
                nested ? bool['must'].push(nested) : "";
                qs['query'] = {'bool': bool};
            } else {
                if ( options.q != "" ) {
                    var qryval = { 'query': fuzzify(options.q) };
                    $('.facetview_searchfield', obj).val() != "" ? qryval.default_field = $('.facetview_searchfield', obj).val() : "";
                    options.default_operator !== undefined ? qryval.default_operator = options.default_operator : false;
                    qs['query'] = {'query_string': qryval };
                } else {
                    qs['query'] = {'match_all': {}};
                };
            };
            // set any paging
            options.paging.from != 0 ? qs['from'] = options.paging.from : "";
            options.paging.size != 100 ? qs['size'] = options.paging.size : "";
            // set any sort or fields options
            options.sort.length > 0 ? qs['sort'] = options.sort : "";
            options.fields ? qs['fields'] = options.fields : "";
            options.partial_fields ? qs['partial_fields'] = options.partial_fields : "";
            // set any facets
            qs['facets'] = {};
            for ( var item = 0; item < options.facets.length; item++ ) {
                var fobj = jQuery.extend(true, {}, options.facets[item] );
                var facet_filter = fobj['facet_filter'];
                delete fobj['display'];
                delete fobj['facet_filter'];
                var facet = {'terms': fobj};
                if (facet_filter || qs['filter']) {
                    facet['facet_filter'] = {'and': []};
                    if (facet_filter) {
                        facet['facet_filter']['and'].push(facet_filter);
                    }
                    if (qs['filter']) {
                        facet['facet_filter']['and'].push(qs['filter']);
                    }
                }
                var parts = fobj['field'].split('.');
                qs['facets'][fobj['field']] = facet;
                for (var ni; ni < options.nested.length; ni++ ) {
                    if (fobj['field'].indexOf(options.nested[i]) == 0) {
                         nested ? qs['facets'][fobj['field']]["scope"] = options.nested[i] : qs['facets'][fobj['field']]["nested"] = options.nested[i];
                    }
                }
            }
            jQuery.extend(true, qs['facets'], options.extra_facets );
            // set elasticsearch filter, if any
            // set any filter
            if (options.filter) {
                qs['filter'] = options.filter;
            }
            //alert(JSON.stringify(qs,"","    "));
            qy = JSON.stringify(qs);
            if ( options.include_facets_in_querystring ) {
                options.querystring = qy;
            } else {
                delete qs.facets;
                options.querystring = JSON.stringify(qs)
            }
            options.sharesave_link ? $('.facetview_sharesaveurl', obj).val('http://' + window.location.host + window.location.pathname + '?source=' + options.querystring) : "";
            return qy;
        };

        //Solr Search
        var solrsearchquery = function() {
            // set default URL params
            var urlparams = "wt=json&";
            for (var item in options.default_url_params) {
                urlparams += item + "=" + options.default_url_params[item] + "&";
            }
            // do paging params
            var pageparams = "";
            for (var item in options.paging) {
                pageparams += options.solr_paging_params[item] + "=" + options.paging[item] + "&";
            }
            // set facet params
            var urlfilters = "";
            for (var item in options.facets) {
                urlfilters += "facet.field=" + options.facets[item]['field'] + "&";
                var size = options.facets[item]['size'] ? options.facets[item]['size'] : 10;
                urlfilters += "f." + options.facets[item]['field'] + ".facet.limit=" + size + "&";
		var sort = 'count';
		if (options.facets[item]['order']) {
		    sort = options.facets[item]['order'];
		    if (sort === 'term' || sort === 'reverse_term') {
			sort = 'index';
		    }
		    else {
			sort = 'count';
		    };
		};
		urlfilters += "f." + options.facets[item]['field'] + ".facet.sort=" + sort + "&";
	    }

	    urlfilters += "facet.mincount=1&";

            if ( options.facets.length > 0 ) {
                urlfilters += "facet=on&";
            }
            // build starting URL
            var theurl = urlparams + pageparams + urlfilters;
            // add default query values
            // build the query, starting with default values
            var query = "";

            $('.facetview_filterselected',obj).each(function() {
                query += $(this).attr('rel') + ':"' +
                $(this).attr('href') + '" AND ';
            });
            // add any freetext filter
            if (options.q != "") {
                query += options.q;
            }
            if (!query.endsWith('*')) {
                query += '*';
            }
            query = query.replace(/ AND $/,"");
            // set a default for blank search
            if (query == "") {
                query = "*:*";
            }
            theurl += options.query_parameter + '=' + query;
            return theurl;
	};
        // execute a search
        var dosearch = function() {
            jQuery('.notify_loading').show();
            // update the options with the latest q value
            if ( options.searchbox_class.length == 0 ) {
                options.q = $('.facetview_freetext', obj).val();
            } else {
                options.q = $(options.searchbox_class).last().val();
            };
            // make the search query
            var qrystr = '';
            var url_1 = options.search_url;;
            if ( options.search_index == "elasticsearch") {
                qrystr = elasticsearchquery();
            } else {
                qrystr = solrsearchquery();
            }

            // augment the URL bar if possible
            if ( options.pushstate ) {
                var currurl = '?source=' + options.querystring;
                window.history.pushState("","search",currurl);
            };
	    jsonp_fname = "";
	    if (options.search_index == "elasticsearch"){
		jsonp_fname = 'callback';
	    }
	    else{
		jsonp_fname = 'json.wrf';
	    }

            $.ajax({
                type: "get",
                url: url_1,
                data: qrystr,
                processData: false,
                dataType: options.datatype,
                jsonp: jsonp_fname,
                success: showresults
            });
        };

        // show search help
        var learnmore = function(event) {
            event.preventDefault();
            $('#facetview_learnmore', obj).toggle();
        };

        // adjust how many results are shown
        var howmany = function(event) {
            event.preventDefault();
            var newhowmany = prompt('Currently displaying ' + options.paging.size +
                ' results per page. How many would you like instead?');
            if (newhowmany) {
                options.paging.size = parseInt(newhowmany);
                options.paging.from = 0;
                $('.facetview_howmany', obj).html(options.paging.size);
                dosearch();
            }
        };

        // change the search result order
        var order = function(event) {
            event.preventDefault();
            if ( $(this).attr('href') == 'desc' ) {
                $(this).html('');
                $(this).attr('href','asc');
                $(this).attr('title','current order ascending. Click to change to descending');
            } else {
                $(this).html('');
                $(this).attr('href','desc');
                $(this).attr('title','current order descending. Click to change to ascending');
            };
            orderby();
        };
        var orderby = function(event) {
            event ? event.preventDefault() : "";
            var sortchoice = $('.facetview_orderby', obj).val();
            if ( sortchoice.length != 0 ) {
                var sorting = {};
                var sorton = sortchoice;
                sorting[sorton] = {'order': $('.facetview_order', obj).attr('href')};
                options.sort = [sorting];
            } else {
                options.sort = [];
            }
            options.paging.from = 0;
            dosearch();
        };

        // parse any source params out for an initial search
        var parsesource = function() {
            var qrystr = options.source.query;
            if (qrystr && 'bool' in qrystr ) {
                var qrys = [];
                // TODO: check for nested
                if ( 'must' in qrystr.bool ) {
                    qrys = qrystr.bool.must;
                } else if ( 'should' in qrystr.bool ) {
                    qrys = qrystr.bool.should;
                };
                for ( var qry = 0; qry < qrys.length; qry++ ) {
                    for ( var key in qrys[qry] ) {
                        if ( key == 'term' ) {
                            for ( var t in qrys[qry][key] ) {
                                if ( !(t in options.predefined_filters) ) {
                                    clickfilterchoice(false,t,qrys[qry][key][t]);
                                };
                            };
                        } else if ( key == 'query_string' ) {
                            typeof(qrys[qry][key]['query']) == 'string' ? options.q = qrys[qry][key]['query'] : "";
                        } else if ( key == 'bool' ) {
                            // TODO: handle sub-bools
                        };
                    };
                };
            } else if (qrystr &&  'query_string' in qrystr ) {
                typeof(qrystr.query_string.query) == 'string' ? options.q = qrystr.query_string.query : "";
            };
        }

        // show the current url with the result set as the source param
        var sharesave = function(event) {
            event.preventDefault();
            $('.facetview_sharesavebox', obj).toggle();
        };

        // adjust the search field focus
        var searchfield = function(event) {
            event.preventDefault();
            options.paging.from = 0;
            dosearch();
        };

        // a help box for embed in the facet view object below
        var thehelp = '
'
        options.sharesave_link ? thehelp += '
Share or save the current search by clicking the share/save arrow button on the right.
' : "";
        thehelp += '
Remove all search values and settings by clicking the X icon at the left of the search box above.
 \

Partial matches with wildcard can be performed by using the asterisk * wildcard. For example, einste*, *nstei*.
 \

Fuzzy matches can be performed using tilde ~. For example, einsten~ may help find einstein.
 \

Exact matches can be performed with " double quotes. For example "einstein" or "albert einstein".
 \

Match all search terms by concatenating them with AND. For example albert AND einstein.
 \

Match any term by concatenating them with OR. For example albert OR einstein.
';
        if ( !options.default_freetext_fuzzify ) {
            thehelp += '
Exclude terms by prefixing them with - (minus sign). For example albert -einstein.
 \

Require terms by prefixing them with + (plus sign). For example albert -physics +einstein (albert is now optional but increases relevance). Full details here.
';
        }

        thehelp += '
Combinations will work too, like albert OR einste~, or "albert" "einstein".
 \

Result set size can be altered by clicking on the result size number preceding the search box above.
';

        if ( options.searchbox_fieldselect.length > 0 ) {
            thehelp += '
By default, terms are searched for across entire record entries. \
                This can be restricted to particular fields by selecting the field of interest from the search field dropdown
';
        };
        if ( options.search_sortby.length > 0 ) {
            thehelp += '
Choose a field to sort the search results by clicking the double arrow above.
';
        };
        if ( options.facets.length > 0 ) {
            thehelp += '

';
            thehelp += '
Use the filters on the left to directly select values of interest. \
                Click the filter name to open the list of available terms and show further filter options.
 \

Filter list size can be altered by clicking on the filter size number.
 \

Filter list order  can be adjusted by clicking the order options - \
                from a-z ascending or descending, or by count ascending or descending.
 \

Filters search for unique values by default; to do an OR search - e.g. to look for more than one value \
                for a particular filter - click the OR button for the relevant filter then choose your values.
 \

To further assist discovery of particular filter values, use in combination \
                with the main search bar - search terms entered there will automatically adjust the available filter values.
';
            if ( options.enable_rangeselect ) {
                thehelp += '
Apply a filter range rather than just selecting a single value by clicking on the range button. \
                    This enables restriction of result sets to within a range of values - for example from year 1990 to 2012.
 \

Filter ranges are only available across filter values already in the filter list; \
                    so if a wider filter range is required, first increase the filter size then select the filter range.
';
            }
        };
        thehelp += '
close the help

';

        // the facet view object to be appended to the page
        var thefacetview = '

';
        if ( options.facets.length > 0 ) {
            thefacetview += '

';
            thefacetview += '
';
        } else {
            thefacetview += '
';
        }
        thefacetview += '

';
        thefacetview += '
';
        thefacetview += '
 \
             \
            ? \
            {{HOW_MANY}}';
        if ( options.search_sortby.length > 0 ) {
            thefacetview += '';
            thefacetview += '
';
            thefacetview += '<select class="facetview_orderby" style="border-radius:5px; \
                -moz-border-radius:5px; -webkit-border-radius:5px; width:100px; background:#eee; margin:0 5px 21px 0;"> \
                <option value="">order by</option>';
            for ( var each = 0; each < options.search_sortby.length; each++ ) {
                var obj = options.search_sortby[each];
                thefacetview += '<option value="' + obj['field'] + '">' + obj['display'] + '</option>';
            };
            thefacetview += '</select>';
        } else {
            thefacetview += '
';
        };
        if ( options.searchbox_fieldselect.length > 0 ) {
            thefacetview += '<select class="facetview_searchfield" style="border-radius:5px 0px 0px 5px; \
                -moz-border-radius:5px 0px 0px 5px; -webkit-border-radius:5px 0px 0px 5px; width:100px; margin:0 -2px 21px 0; background:' + options.searchbox_shade + ';">';
            thefacetview += '<option value="">search all</option>';
            for ( var each = 0; each < options.searchbox_fieldselect.length; each++ ) {
                var obj = options.searchbox_fieldselect[each];
                thefacetview += '<option value="' + obj['field'] + '">' + obj['display'] + '</option>';
            };
            thefacetview += '</select>';
        };
        thefacetview += '<input type="text" class="facetview_freetext span4" style="display:inline-block; margin:0 0 21px 0; background:' + options.searchbox_shade + ';" name="q" \
            value="" placeholder="search term" />';
        if ( options.sharesave_link ) {
            thefacetview += '';
            thefacetview += '
 \
                <button type="button" class="facetview_sharesave close">×</button> \

Share or save this search:
 \
                <textarea class="facetview_sharesaveurl" style="width:100%;height:100px;">http://' + window.location.host +
                window.location.pathname + '?source=' + options.querystring + '</textarea> \

';
        }
        thefacetview += '
';
        thefacetview += thehelp;
        thefacetview += '

';
        options.pager_on_top ? thefacetview += '

' : "";
        thefacetview += options.searchwrap_start + options.searchwrap_end;
        thefacetview += '

';

        var obj = undefined;

        // ===============================================
        // now create the plugin on the page
        return this.each(function() {
            // get this object
            obj = $(this);

            // what to do when ready to go
            var whenready = function() {
                // append the facetview object to this object
                thefacetview = thefacetview.replace(/{{HOW_MANY}}/gi,options.paging.size);
                obj.append(thefacetview);
                !options.embedded_search ? $('.facetview_search_options_container', obj).hide() : "";

                // bind learn more and how many triggers
                $('.facetview_learnmore', obj).bind('click',learnmore);
                $('.facetview_howmany', obj).bind('click',howmany);
                $('.facetview_searchfield', obj).bind('change',searchfield);
                $('.facetview_orderby', obj).bind('change',orderby);
                $('.facetview_order', obj).bind('click',order);
                $('.facetview_sharesave', obj).bind('click',sharesave);

                // check paging info is available
                !options.paging.size && options.paging.size != 0 ? options.paging.size = 10 : "";
                !options.paging.from ? options.paging.from = 0 : "";

                // handle any source options
                if ( options.source ) {
                    parsesource();
                    delete options.source;
                }

                // set any default search values into the search bar and create any required filters
                if ( options.searchbox_class.length == 0 ) {
                    options.q != "" ? $('.facetview_freetext', obj).val(options.q) : "";
                    buildfilters();
                    $('.facetview_freetext', obj).bindWithDelay('keyup',dosearch,options.freetext_submit_delay);
                } else {
                    options.q != "" ? $(options.searchbox_class).last().val(options.q) : "";
                    buildfilters();
                    $(options.searchbox_class).bindWithDelay('keyup',dosearch,options.freetext_submit_delay);
                }

                options.source || options.initialsearch ? dosearch() : "";

            };

            // check for remote config options, then do first search
            if (options.config_file) {
                $.ajax({
                    type: "get",
                    url: options.config_file,
                    dataType: "jsonp",
                    success: function(data) {
                        options = $.extend(options, data);
                        whenready();
                    },
                    error: function() {
                        $.ajax({
                            type: "get",
                            url: options.config_file,
                            success: function(data) {
                                options = $.extend(options, $.parseJSON(data));
                                whenready();
                            },
                            error: function() {
                                whenready();
                            }
                        });
                    }
                });
            } else {
                whenready();
            }

        }); // end of the function

    };

    // facetview options are declared as a function so that they can be retrieved
    // externally (which allows for saving them remotely etc)
    $.fn.facetview.options = {};

})(jQuery);