https://github.com/arillo/backbone.facetr
A library to perform faceted search on Backbone collections
https://github.com/arillo/backbone.facetr
Last synced: about 1 year ago
JSON representation
A library to perform faceted search on Backbone collections
- Host: GitHub
- URL: https://github.com/arillo/backbone.facetr
- Owner: arillo
- License: other
- Created: 2013-02-13T14:45:24.000Z (over 13 years ago)
- Default Branch: master
- Last Pushed: 2016-01-14T16:48:12.000Z (over 10 years ago)
- Last Synced: 2025-04-14T19:07:57.422Z (about 1 year ago)
- Language: JavaScript
- Homepage: http://arillo.github.io/Backbone.Facetr/
- Size: 708 KB
- Stars: 47
- Watchers: 14
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Backbone.Facetr
[](https://www.npmjs.com/package/backbone.facetr)
[](https://www.npmjs.com/package/backbone.facetr)
[](https://github.com/arillo/Backbone.Facetr)
[](https://travis-ci.org/arillo/Backbone.Facetr)
[](https://coveralls.io/github/arillo/Backbone.Facetr?branch=master)
* [INTRODUCTION](#introduction)
* [INSTALLATION](#installation)
* [BASIC USAGE](#basic-usage)
* [DOT NOTATION](#dot-notation)
* [OPERATORS](#operators)
* [API REFERENCE](#api-reference)
* [EXAMPLES](#examples)
* [LICENSE](#license)
Backbone.Facetr is an utility which enables filtering of Backbone collections through facets. It can be used to implement faceted search, which follows the
[faceted classification system](http://en.wikipedia.org/wiki/Faceted_classification).
It works flawlessly up to 2500 items; computation starts getting slower with 5000 - 10000 items. This is however an
early version; optimizations may improve performance in future realeases.
Production bundles can be found in the dist folder. Facetr is distributed via bower and npm.
Both AMD and CommonJS are supported.
#### npm
```bash
npm install backbone.facetr --save
```
#### bower
```bash
bower install Backbone.Facetr --save
```
#### build from source
```bash
git clone git@github.com:arillo/Backbone.Facetr.git # clone repo
cd Backbone.Facetr # navigate to local repo
npm install -g grunt-cli # install grunt globally
npm install # install dependencies
grunt # build to dist folder
```
Include in your code using any of the following methods
#### AMD
```js
define('yourmodule', ['backbone.facetr'], function(Facetr){
// ...
});
```
#### CommonJS
```js
var Facetr = require('backbone.facetr');
```
#### script tag
```html
```
```js
// create a collection with few test items
var collection = new Backbone.Collection([
{
'Name' : {
'FirstName' : 'Bob',
'LastName' : 'Smith'
},
'Age' : 20,
'Country' : 'Australia',
'Hobbies' : ['fishing','painting','playing the ukulele'],
'Profession': 'manager'
},
{
'Name' : {
'FirstName' : 'Otto',
'LastName' : 'Von Braun'
},
'Age' : 35,
'Country' : 'New Zealand',
'Hobbies' : ['drawing', 'painting', 'shopping'],
'Profession': 'team manager'
},
{
'Name' : {
'FirstName' : 'Sarah',
'LastName' : 'Smith'
},
'Age' : 28,
'Country' : 'Ireland',
'Hobbies' : ['shopping','painting'],
'Profession': 'project manager'
}
]);
Facetr(collection).facet('Name.LastName').value('Smith'); // collection contains 'Sarah Smith' and 'Bob Smith'
Facetr(collection).facet('Hobbies').value('shopping'); // contains only 'Sarah Smith'
Facetr(collection).facet('Name.LastName').removeValue('Smith'); // contains 'Sarah Smith' and 'Otto Von Braun'
// removes all facet values and restores original collection content
Facetr(collection).clearValues();
// if chaining is not your cup of tea, the following is equivalent to the above code
var facetCollection = Facetr(collection); // returns a FacetCollection object
var lastNameFacet = facetCollection.facet('Name.LastName'); // returns a Facet object
var hobbiesFacet = facetCollection.facet('Hobbies');
lastNameFacet.value('Smith'); // returns a FacetExp object
hobbiesFacet.value('shopping');
lastNameFacet.removeValue('Smith');
// read the API Reference section for more
// most examples will use the above collection reference to illustrate functionalities
```
Syntax: PropertyName{1}(.PropertyName)*
In the context of Facetr, Dot Notation refers to the syntax used to define facets on a collection. Using the
Facetr Dot Notation it is possible to define facets on properties of a Model, as well as on properties of its properties.
For example, consider the following model:
```js
var model = new Backbone.Model({
'Name' : {
'FirstName' : 'John',
'LastName' : ['Smith','White']
},
'City' : 'London',
'Age' : 45,
'FamilyMembers' : [
{ 'Name' : 'Robert' },
{ 'Name' : 'Margaret' }
]
});
```
To add a facet on property 'FirstName' the following expression in Dot Notation syntax can be used: 'Name.FirstName'.
```js
Facetr(collection).facet('Name.FirstName');
```
Theoretically there is no depth limit for a Dot Notation expression (e.g. PropertyName1.PropertyName2...PropertyNameN), the only
limitation being the common sense.
A facet can only be added on a Backbone Model or object property having any of the following value types:
* string | number | boolean
* Array of strings
* Array of numbers
* Array of booleans
* Array of objects
* Array of Backbone models
It cannot be added on properties having the following value / composite types:
* object
* Backbone Collection
* Array of arrays
* Array of Backbone collections
.. and in any other case not mentioned in the list of allowed value types
#### EXAMPLE
```js
Facetr(collection).facet('City'); // valid, City is a string
Facetr(collection).facet('Age'); // valid, Age is a Number
Facetr(collection).facet('Name.LastName'); // valid, LastName is an Array of strings
Facetr(collection).facet('FamilyMembers.Name'); // valid, takes value of Name of each object in array FamilyMembers
Facetr(collection).facet('Name'); // error, Name is an object
// etc..
```
Facets filtering can be combined using logical operators 'or' and 'and', both between different facets (external operator, see [FacetCollection.facet method](#facetcollection-facet)) and between values of one facet (internal operator, see [Facet.value method](#facet-value) and [FacetExp](#facetexp)).
#### External Operator
```js
// create a facet with default external operator 'and'
var facetCountry = Facetr(collection).facet('Country');
// or set the external operator explicitly
var facetLastName = Facetr(collection).facet('Name.LastName', 'and');
// when filtering, such operator will be used to combine filters of the two facets
facetCountry.value('Australia');
facetLastName.value('Smith');
// collection contains all models with Country equal 'Australia' and LastName equal 'Smith'
```
#### Internal Operator
```js
// add a value with default internal operator 'or'
facetCountry.value('Australia');
// or set the internal operator explicitly
facetCountry.value('Ireland', 'or');
// it is possible to use chaining syntax to combine values
facetCountry.value('Australia').or('Ireland');
// collection contains all models with Country equal either 'Australia' or 'Ireland'
```
* [Facetr](#facetr)
* [FacetCollection](#facetcollection)
* [facet](#facetcollection-facet)
* [toJSON](#facetcollection-tojson)
* [clear](#facetcollection-clear)
* [remove](#facetcollection-remove)
* [sortBy](#facetcollection-sortby)
* [asc](#facetcollection-asc)
* [desc](#facetcollection-desc)
* [addFilter](#facetcollection-addfilter)
* [removeFilter](#facetcollection-removefilter)
* [clearFilters](#facetcollection-clearfilters)
* [clearValues](#facetcollection-clearvalues)
* [facetsOrder](#facetcollection-facetsorder)
* [collection](#facetcollection-collection)
* [origLength](#facetcollection-origlength)
* [facets](#facetcollection-facets)
* [settingsJSON](#facetcollection-settingsjson)
* [initFromSettingsJSON](#facetcollection-initfromsettingsjson)
* [Facet](#facet)
* [value](#facet-value)
* [removeValue](#facet-removevalue)
* [toJSON](#facet-tojson)
* [label](#facet-label)
* [sortByCount](#facet-sortbycount)
* [sortByActiveCount](#facet-sortbyactivecount)
* [sortByValue](#facet-sortbyvalue)
* [asc](#facet-asc)
* [desc](#facet-desc)
* [remove](#facet-remove)
* [clear](#facet-clear)
* [customData](#facet-customdata)
* [isSelected](#facet-isselected)
* [hierarchy](#facet-hierarchy)
* [FacetExp](#facetexp)
* [and](#facetexp-and)
* [or](#facetexp-or)
### Facetr
##### Facetr(collection:Backbone.Collection, [id:string]) : FacetCollection
Initialize a Collection to be used with Facetr. The first building block of
any Facetr expression. Returns the created FacetCollection instance for
method chaining. An id can be associated with the collection.
**Example**
```js
Facetr(collection);
// or also
Facetr(collection, 'myCollection');
// which enables the following syntax
Facetr('myCollection') === Facetr(collection); // true
```
##### facet(dotNotationExpr:string, [externalOperator:string], [silent:boolean]) : Facet
Adds a Facet on the given collection using the property refered to by the
Dot Notation expression (see [Dot Notation section](#dot-notation) for more details).
Valid [external operator](#operators) values are: 'or' and 'and' (default is 'and').
Returns the created Facet instance to allow method chaining.
Triggers a facet event with the facetName passed to the callback, unless true is passed as last parameter.
**Example**
```js
Facetr(collection).on('facet', function(facetName) {
console.log('added facet', facetName);
});
// add facet on property 'Age' using default operator ('and')
Facetr(collection).facet('Age');
// add facet on property 'LastName' of object 'Name' using 'or' operator
Facetr(collection).facet('Name.LastName', 'or');
// console output would be
// added facet Age
// added facet Name.LastName
```
Returns an array containing objects representing the status of the facets
added to the collection. Useful for rendering out facets lists.
Each object in the array is the result of invoking toJSON on each Facet
(see Facet documentation below for the Facet.toJSON method).
**Example**
```js
// create a collection with two models
var collection = new Backbone.Collection([
{
'Name' : {
'FirstName' : 'Bob',
'LastName' : 'Smith'
},
'Age' : 20
},
{
'Name' : {
'FirstName' : 'Otto',
'LastName' : 'Von Braun'
},
'Age' : 35
}
]);
Facetr(collection).facet('Name.FirstName').label('First Name');
Facetr(collection).facet('Name.FirstName').value('Bob');
var json = Facetr(collection).toJSON();
// value of json will be an array of Facet data object with the following format:
//
// [
// {
// data : {
// extOperator : 'and',
// intOperator : 'or',
// label : 'First Name',
// name : 'Name.FirstName',
// selected : true,
// sort : {
// by : 'value',
// direction : 'asc'
// }
// customData : {}
// },
// values : [
// {
// active : true,
// activeCount : 1,
// count : 1,
// value : 'Bob'
// },
// {
// active : false,
// activeCount : 0,
// count : 1,
// value : 'Otto'
// }
// ]
// }
// ]
```
##### clear([silent:boolean]) : FacetCollection
Removes all the facets added to the collection and unfilters it accordingly.
Use this method to reset the original models in the collection.
Triggers a clear event, unless true is passed as parameter.
**Example**
```js
Facet(collection).on('clear', function() {
console.log('All facets were removed');
});
Facet(collection).clear();
// console output:
// All facets were removed
```
Removes all the facets and the facetrid added on the collection id upon
Facetr(collection) initialization. Resets the original items in the
collection.
**Example**
```js
Facetr(collection).remove()
```
##### sortBy(attribute:string, [silent]) : FacetCollection
Sorts the collection according to the given attribute name. By default
ascendent sort is used. See asc() and desc() methods below to define sort
direction. Triggers sort event unless true is passed as last parameter.
This method automatically recognizes string, numeric or date values.
**Example**
```js
Facetr(collection).on('sort', function(attr, dir) {
console.log('Sorting by ' + attr + ' ' + dir);
});
Facetr(collection).sortBy('Age');
// console output:
// Sorting by Age asc
```
##### asc([silent:boolean]) : FacetCollection
Sorts the collection in ascendent order by the attribute selected using
sortBy method.
If sortBy was not invoked before, this method has no effect. Triggers sort
event unless true is passed as parameter.
**Example**
```js
Facetr(collection).sortBy('Age').asc();
```
##### desc([silent:boolean]) : FacetCollection
Sorts the collection in descendent order by the attribute selected using
sortBy method.
If sortBy was not invoked before, this method has no effect. Triggers sort
event unless true is passed as parameter.
**Example**
```js
Facetr(collection).sortBy('Age').desc();
```
##### addFilter(filterName:string, filter:function, [silent:boolean]) : FacetCollection
Adds a filter which is used to filter the collection by testing each model against it.
Triggers Backbone.Collection reset unless true is passed as last parameter. Multiple filters can be added as long as they have
different names. Adding two filters with the same name will result in the first being overwritten by the second.
**Example**
```js
Facetr(collection).addFilter('AgeFilter', function(model) {
return model.get('Age') >= 20 && model.get('Age') < 60;
});
```
##### removeFilter(filterName:string, [silent:boolean]) : FacetCollection
Removes the filter with the given name from the collection and unfilters it accordingly.
Triggers reset unless true is passed as last parameter.
**Example**
```js
Facetr(collection).removeFilter('AgeFilter');
```
##### clearFilters([silent:boolean]) : FacetCollection
Removes all the filters previously added to the collection and unfilters it accordingly.
Triggers reset unless true is passed as parameter.
**Example**
```js
Facetr(collection).clearFilters();
```
##### clearValues([silent:boolean]) : FacetCollection
Removes all the currently selected values from all the facets, bringing
the collection to its initial state.
Triggers a clearValues event unless true is passed as parameter.
**Example**
```js
Facetr(collection).clearValues();
```
##### facetsOrder(facetNames:Array, [silent:boolean]) : FacetCollection
Sometimes it is convinient to give the facets list a predefined order. This method
can be used to achieve this by passing an array of facet names which corresponds to
the order to be given to the facets in the list. Triggers a 'facetsOrder' event with the facetNames array passed
to the event handler, unless true is given as last parameter.
**Example**
```js
Facetr(collection).facet('Age');
Facetr(collection).facet('Name.FirstName');
// Facetr(collection).toJSON() has facet 'Age' at index 0 and 'Name.FirstName' at index 1
Facetr(collection).facetsOrder(['Name.FirstName', 'Age']);
// Facetr(collection).toJSON() has facet 'Name.FirstName' at index 0 and 'Age' at index 1
```
##### collection() : Backbone.Collection
Returns the reference to the Backbone.Collection. Useful for cases where the reference
is needed but it was declared in another scope and is no more accessible.
**Example**
```js
Facetr(collection).collection() === collection; // true
```
Returns the length of the collection before any faceted filtering was applied.
**Example**
```js
var collection = new Backbone.Collection([
{
Name : 'John'
Age : 19
},
{
Name : 'Sarah',
Age : 35
}
]);
collection.length() // 2
Facetr(collection).facet('Age').value(35);
collection.length(); // 1
Facetr(collection).origLength(); // 2
```
Returns an array containing all the Facet instances created on this FacetCollection.
Returns an object representation of the current state of the Facetr collection which
can be used to reload the same state in future using the initFromSettingsJSON method.
**Example**
```js
Facetr(collection).facet('Name.FirstName').label('First Name');
Facetr(collection).sortBy('Name.FirstName').asc();
Facetr(collection).facet('Name.FirstName').value('Bob');
var json = Facetr(collection).settingsJSON();
// value of json will be the following:
//
// {
// sort : {
// by : "Name.FirstName",
// dir : "asc"
// },
// facets : [
// {
// attr : "Name.FirstName",
// eop : "and",
// iop : "or",
// vals : [ "Bob" ]
// }
// ]
// }
```
##### initFromSettingsJSON(json:object) : FacetCollection
Initializes the Facetr collection using a settings object generated
using the settingsJSON method. Triggers an "initFromSettingsJSON" event.
##### value(value:string, [internalOperator:string], [silent:boolean]) : FacetExp
Adds a value to the facet. This will result in the collection being filtered
by { FacetName : 'Value' }. Valid [internal operator](#operators) values are: 'or' and 'and' (default is 'or').
Triggers a 'filter' event on the FacetCollection passing facetName and facetValue to the handler and
a 'value' event on the Facet passing the facetValue to the handler, unless true is passed
as last parameter.
**Example**
```js
Facetr(collection).on('filter', function(facetName, facetValue) {
console.log('filtered by '+ facetName + ' with value equal ' + facetValue);
});
var facet = Facetr(collection).facet('Name.FirstName');
facet.on('value', function(facetValue){
console.log('the following value was added to the facet: ' + facetValue);
});
facet.value('Bob');
// console output: "filtered by Name.FirstName with value Bob"
// collection contains only models with FirstName = 'Bob'
```
##### removeValue(value:string, [silent:boolean]) : FacetExp
Removes the given value from the facet and resets the collection to
the state previous of the filtering caused by the removed value.
Triggers a 'unfilter' event on the FacetCollection passing facetName and facetValue to the handler and
a 'removeValue' event on the Facet passing the facetValue to the handler, unless true is passed
as last parameter.
**Example**
```js
Facetr(collection).on('unfilter', function(facetName, facetValue) {
console.log('unfiltered by '+ facetName + ' with value equal ' + facetValue);
});
var facet = Facetr(collection).facet('Name.FirstName');
facet.on('removeValue', function(value){
console.log('the following value was removed from the facet: ' + value);
});
facet.removeValue('Bob');
// console output: "unfiltered by Name.FirstName with value Bob"
// collection contains again also models with FirstName = 'Bob'
```
Returns an object representation of the current facet data and values.
Useful for rendering the facet to the page.
**Example**
```js
// create a collection with two models
var collection = new Backbone.Collection([
{
'Name' : {
'FirstName' : 'Bob',
'LastName' : 'Smith'
},
'Age' : 20
},
{
'Name' : {
'FirstName' : 'Otto',
'LastName' : 'Von Braun'
},
'Age' : 35
}
]);
Facetr(collection).facet('Name.FirstName').label('First Name');
Facetr(collection).facet('Name.FirstName').value('Bob');
var json = Facetr(collection).facet('Name.FirstName').toJSON();
// json is equal to:
//
// {
// data : {
// extOperator : 'and',
// intOperator : 'or',
// label : 'First Name',
// name : 'Name.FirstName',
// selected : true,
// sort : {
// by : 'value',
// direction : 'asc'
// }
// customData : {}
// },
// values : [
// {
// active : true,
// activeCount : 1,
// count : 1,
// value : 'Bob'
// },
// {
// active : false,
// activeCount : 0,
// count : 1,
// value : 'Otto'
// }
// ]
// }
```
##### label(label:string) : Facet
Use this method to set a human readable label for the facet.
This can be used when rendering the facet on the page.
**Example**
```js
Facetr(collection).facet('Name.FirstName').label('First Name');
Facetr(collection).facet('Name.FirstName').toJSON();
// the property data.label has value 'First Name'
// while the property data.name stays 'Name.FirstName'
```
Sorts the facet values by their count. The count is the number
of models in the original collection with an attribute having as name
the facet name and value the given value.
**Example**
```js
// we use the colleciton defined in Basic Usage section
var facet = Facetr(collection).facet('Hobbies');
facet.value('painting'); // painting count = 3
facet.value('drawing'); // drawing count = 1
// facet.toJSON().data.values[0] = 'drawing'
// facet.toJSON().data.values[1] = 'painting'
facet.sortByCount();
// facet.toJSON().data.values[0] = 'painting'
// facet.toJSON().data.values[1] = 'drawing'
```
##### sortByActiveCount() : Facet
Sorts the facet values by their active count. The active count is the number
of models in the current filtered collection with an attribute having as name
the facet name and value the given value.
**Example**
```js
var facet = Facetr(collection).facet('Hobbies');
facet.value('fishing');
facet.value('shopping');
// fishing active count = 1
// shopping active count = 2
// facet.toJSON().data.values[0] = 'fishing'
// facet.toJSON().data.values[1] = 'shopping'
facet.sortByActiveCount();
// facet.toJSON().data.values[0] = 'shopping'
// facet.toJSON().data.values[1] = 'fishing'
```
Sorts the facet values by their value. This is the default sort.
Sets the direction of the values sort to ascendent.
**Example**
```js
Facetr(collection).facet('Name.FirstName').asc();
```
Sets the direction of the values sort to descendant.
**Example**
```js
Facetr(collection).facet('Name.FirstName').sortByCount().desc();
```
##### remove([silent:boolean]) : undefined
Removes the facet and all its values and unfilters the collection accordingly.
It triggers a "removeFacet" event on the facet collection, unless true is passed as parameter.
```js
var facetCollection = Facetr(collection);
var facet = facetCollection.facet('Age');
facetCollection.on('removeFacet', function(facetName){
console.log('removed facet', facetName);
});
facet.remove();
// console output would be
// removed facet Age
```
##### clear([silent:boolean]) : Facet
Unselects all the values from the facet. It triggers a 'clear' event unless true is passed as parameter.
##### customData(key:string, [value:object]) : Facet
This method can be used to add arbitrary data to pass to the templates.
Data added using this method is included in the object returned by the toJSON() method
in the data.customData property.
To retrieve previously set data, just pass the key parameter without any value.
**Example**
```js
var facet = Facetr('myCollection').facet('Hobbies').customData('sublabel', 'Available hobbies');
// facet.customData('sublabel') returns 'Available hobbies'
// facet.toJSON().data.customData = { sublabel : 'Available hobbies' }
```
Returns true if any value is selected from this facet, false otherwise.
**Example**
```js
var facet = Facetr('myCollection').facet('Hobbies');
facet.value('fishing');
// facet.isSelected() returns true
facet.clear(); // remove all selected values
// facet.isSelected() returns false
```
##### hierarchy(hierarchySettings:Array) : Facet
This method creates a hierarchical representation of facet values, based on the settings
object given as parameter. Once this method is used, the facet becomes a "hierarchical" facet.
You can then use the facet as you usually would, with the following differences:
* the data section of the object resulting from invoking the toJSON method will also
contain a "hierarchical" property with value true and a "groupedValues" array, with the following format:
groupedValues
```js
[
{
value: "manager",
label: "Manager",
active: false,
activeCount: 7,
count: 7,
groups: [
{
value: "team manager",
label: "Team Manager",
active: false,
activeCount: 5,
count: 5,
groups: [
{ ... other groups values ... }
]
},
{
value: "manager",
label: "Manager",
active: false,
activeCount: 5,
count: 5 // no groups property means that this value has no children groups
},
]
}
]
```
* when a value from the facet is selected, also the models resulting from selecting its descendents values are
included in the result set
* the count includes both the count of the value itself and that of its descendants values
The hierarchySettings argument is an array with different "hierarchical value" objects, where it is possible
to specify the hierarchy of values along with a label. See the **Example** below to understand the hierarchySettings format.
**Example**
```js
var hierarchySettings = [
{
value: "manager",
label: "Manager",
groups: [
{
value: "project manager",
label: "Project Manager",
groups: [
{
value: "team manager",
label: "Team Manager"
}
]
}
]
}
];
var profession = Facetr(collection).facet('Profession').hierarchy(hierarchySettings);
var json = profession.toJSON();
// value of json variable would be:
//
// {
// "data": {
// "name":"Profession",
// "hierarchical":true,
// "label":"Profession",
// "extOperator":"and",
// "intOperator":"or",
// "sort":{
// "by":"activeCount",
// "direction":"desc"
// },
// "selected":false,
// "customData":{}
// },
// "values": [ ... stays as the normal facets ... ],
// "groupedValues":[
// {
// "value":"manager",
// "label":"Manager",
// "active":false,
// "activeCount":3,
// "count":3,
// "groups":[
// {
// "value":"project manager",
// "label":"Project Manager",
// "active":false,
// "activeCount":2,
// "count":2,
// "groups":[
// {
// "value":"team manager",
// "label":"Team Manager",
// "active":false,
// "activeCount":1,
// "count":1
// }
// ]
// }
// ]
// }
// ]
// }
```
FacetExp objects are returned from Facet value and removeValue methods.
They can be used to coincisely define multiple values on a facet, using
different operators.
**Example**
```js
Facetr(collection).facet('Age').value(12, 'and');
Facetr(collection).facet('Age').value(15, 'or');
Facetr(collection).facet('Age').value(39, 'and');
// can also be expressed with the following syntax
Facetr(collection).facet('Age').value(12, 'and').or(15).and(39);
```
##### and(value:string, [silent:boolean]) : Facet
Equivalent to facet.value('Value', 'and'), but can be used for FacetExp chains.
##### or(value:string, [silent:boolean]) : Facet
Equivalent to facet.value('Value', 'or'), but can be used for FacetExp chains.
This section contains a list of websites / projects using Facetr.
* [ruefer-ing.ch](http://ruefer-ing.ch/referenzen)
* [terra-vecchia.ch](http://terra-vecchia.ch/sozialtherapie/angebote-und-betriebe)
* [grimselhydro.ch](http://grimselhydro.ch/referenzen)
Backbone.Facetr may be freely distributed under the MIT license.
Copyright (C) 2012 Arillo GmbH http://arillo.net
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.