cluster_search_ui/commit

Cleaned up code.

authorChris Dijkshoorn
Sat Dec 13 15:42:56 2014 +0100
committerChris Dijkshoorn
Sat Dec 13 15:42:56 2014 +0100
commitd0fc16e1ad5d3b116422e80a149908148813b548
tree16d07c3df8cd2554e10be068ed97952290aa9006
parent0d6e0aa440b1cab87aeb7712c2116a0d95f046b2
Diff style: patch stat
diff --git a/api/cluster_search_ui.pl b/api/cluster_search_ui.pl
index 42cf75a..39fa995 100644
--- a/api/cluster_search_ui.pl
+++ b/api/cluster_search_ui.pl
@@ -1,371 +1,101 @@
-:- module(cluster_search_ui, [cluster_search/2]).
+:- module(cluster_search_ui, []).
 
-% http library
+/** <module> Generation of web ui for cluster search
+
+This module is used for generating HTML elements for the ui for cluster
+search. It is able to generate 4 different types of pages:
+
+  * front   - frontpage with a carousel of search examples
+  * results - results page depicting the search results
+  * result  - one result and its metadata
+  * about   - information about the system
+
+The ui variables are retrieved from rdf (e.g. rdf/rijksmuseum_ui.ttl).
+*/
+
+:- use_module(library(cluster_search_ui/web_ui_dcg)).
+:- use_module(library(cluster_search_ui/settings)).
 :- use_module(library(http/http_ssl_plugin)).
 :- use_module(library(http/http_dispatch)).
 :- use_module(library(http/http_server_files)).
-:- use_module(library(http/http_json)).
-:- use_module(library(http/http_open)).
-:- use_module(library(http/url_cache)).
-:- use_module(library(http/http_parameters)).
+:- use_module(library(http/html_write)).
+:- use_module(library(http/html_head)).
 :- use_module(library(http/http_path)).
-
-% semweb modules
+:- use_module(library(http/http_parameters)).
 :- use_module(library(semweb/rdf_db)).
-:- use_module(library(semweb/rdf_label)).
-
-% register namespaces
-:- rdf_register_prefix(rma, 'http://purl.org/collections/nl/rma/schema#').
-:- rdf_register_prefix(rmaterms, 'http://purl.org/collections/nl/rma/terms/').
-:- rdf_register_prefix(edm, 'http://www.europeana.eu/schemas/edm/').
-:- rdf_register_prefix(gvp, 'http://vocab.getty.edu/ontology#').
-:- rdf_register_prefix(aat, 'http://vocab.getty.edu/aat/').
-:- rdf_register_prefix(ulan, 'http://purl.org/vocabularies/getty/ulan/').
-
-% util modules
-:- use_module(library(cluster_search/rdf_cluster)).
-:- use_module(library(cluster_search/rdf_search)).
-:- use_module(library(cluster_search/iface_util)).
-:- use_module(library(cluster_search_ui/settings)).
-%:- use_module(library(cluster_search/search_statistics)).
-
-% search modules
-:- use_module(library(cluster_search/graph_search)).
-
-% output modules
-:- use_module(library(cluster_search/web_ui)).
 
 
 % construct url and define filesystem search paths
 http:location(fonts, cliopatria(fonts), []).
 http:location(img, cliopatria(img), []).
-http:location(analysis, cliopatria(analysis), []).
 user:file_search_path(fonts, web(fonts)).
 user:file_search_path(img, web(img)).
-user:file_search_path(analysis, web(analysis)).
 
-:- http_handler(cliopatria(ui), web, []).
-:- http_handler(cliopatria(search), results, []).
+:- http_handler(cliopatria(search), search, []).
+:- http_handler(cliopatria(results), results, []).
 :- http_handler(cliopatria(about), about, []).
-:- http_handler(cliopatria(item), result, []).
-:- http_handler(cliopatria(analytics), analytics, []).
-:- http_handler(cliopatria(json), search_api,  []).
+:- http_handler(cliopatria(item), item, []).
 :- http_handler(fonts('.'), serve_files_in_directory(fonts), [prefix]).
 :- http_handler(img('.'), serve_files_in_directory(img), [prefix]).
-:- http_handler(analysis('.'), serve_files_in_directory(analysis), [prefix]).
-
-%%	search_api(+Request)
-%
-%	Retrieves clusters of search results, according to the query.
-%	First it gets the url parameters, second it executes graph
-%	search algorithm. The resulting clusters are enriched with
-%	metadata, after which the data is prepared for output and
-%	outputted as json.
-search_api(Request) :-
-    get_parameters(Request, Options),
-    cluster_search(Clusters, Options),
-    enrich(Clusters, EnrichedClusters, Options),
-    write_data(EnrichedClusters).
-
-%%	get_parameters(+Request, -Options)
-%
-%	Retrieves an option list of parameters from the url.
-get_parameters(Request, Options) :-
-    http_parameters(Request,
-	[query(Query, [description('Entered Query'), optional(false)])
-	]),
-    Options = [query(Query)].
-
-%%	cluster_search(-Clusters, +Options)
-%
-%	Executes a graph search algorithm according to given options.
-%	SearchResults is a list of score-resource pairs acquired by
-%	searching the RDF Graph. SearchState contains the search history
-%	including the search graph.
-cluster_search(Clusters, Options) :-
-    option(query(Query), Options),
-    debug(query, 'cluster_search Query: ~p', [Query]),
-    SearchOptions = [graphOutput(spo)],
-    graph_search(Query, State, SearchOptions),
-    rdf_search_property(State, targets(SearchResults)),
-    OrganizeOptions = [groupBy(path)],
-    organize_resources(SearchResults, State, Clusters, OrganizeOptions).
-
-%%	write_data(+Data, +Options)
-%
-%	Write data in JSON format to output stream.
-write_data(clusters(Clusters)) :-
-    clusters_to_json(Clusters, JsonClusters),
-    Json = json([clusters=JsonClusters]),
-    reply_json(Json).
-
-%%	clusters_to_json(+Clusters, -JsonResults)
-%
-%	Converts clusters to prolog terms appropriate for json output.
-clusters_to_json([],[]).
-clusters_to_json([Cluster|Clusters], [JsonCluster|JsonResults]) :-
-    cluster_info(Cluster, Path, ClusterItems),
-    length(ClusterItems, NumberOfResults),
-    items_to_json(ClusterItems, JsonItems),
-    path_to_json(Path, JsonPath),
-    JsonCluster = json([path=JsonPath, results=NumberOfResults, items=JsonItems]),
-    clusters_to_json(Clusters, JsonResults).
-
-cluster_info(Path - Items, Path, Items).
-
-%%	items_to_json(+Clusters, -JsonResults)
-%
-%	Converts items to prolog terms appropriate for json output.
-items_to_json([], []).
-items_to_json([item(Uri,ThumbnailUrl,Link,Title)|Results], [Item|JsonItems]) :-
-    Item = json([uri=Uri,thumb=ThumbnailUrl,link=Link,title=Title]),
-    items_to_json(Results, JsonItems).
-
-%%	items_to_json(+Clusters, -JsonResults)
-%
-%	Converts the path to prolog terms appropriate for json output.
-path_to_json([], []).
-path_to_json([step(Uri, Label)|Path], [JsonStep|JsonPath]) :-
-    JsonStep = json([uri=Uri, label=Label]),
-    path_to_json(Path, JsonPath).
-
-
-/***************************************************
-* result organization
-***************************************************/
-
-%%	organize_resources(+Targets, +Graph, -Data, +Options)
-%
-%	Data is a structure containing Targets
-organize_resources(Targets, State, clusters(Clusters), Options) :-
-    option(groupBy(GroupBy), Options),
-    option(start(Start), Options, 0),
-    option(end(End), Options, 100),
-    search_graph(State, SearchGraph),
-    group_targets_by_value(GroupBy, Targets, SearchGraph, Clusters0, Options),
-    cluster_select(Clusters0, Start, End, Clusters).
 
-search_graph(State, Graph) :-
-    rdf_search_property(State, graph(Graph)), !.
-search_graph(_, []).
+:- set_setting_default(thumbnail:thumbnail_size, size(350,300)).
+:- set_setting_default(thumbnail:medium_size, size(1280,1024)).
+:- set_setting_default(search:image_filter, all).
 
-%%	group_items_by_value(+GroupBy, +Targets, +SearchGraph, -Clusters, +Options)
+%%	search(+Request) is det.
 %
-%	Clusters is a list of pairs with key is a value of GroupBy and
-%	the value a list of corresponding elements from Items.
-group_targets_by_value(GroupBy, Targets, Graph, Clusters, Options) :-
-    memberchk(GroupBy, [path,spath]),
-    setting(search:search_path, Default),
-    option(searchPath(Method), Options, Default),
-    result_paths(Targets, Method, GroupBy, Graph, Pairs0),
-    keysort(Pairs0, Pairs),
-    group_pairs_by_key(Pairs, Clusters).
+%	Generate front page.
+search(_Request) :-
+    reply_page(front, _Options).
 
-%%	result_paths(+Targets:score-resource, +Method, +Abstract, +Graph, -Items:item(Resource,Score,Path)) is det.
+%%	results(+Request) is det.
 %
-%	Add path between resource and query.
-result_paths(Targets, Method, Abstract, Graph, Items) :-
-    empty_path_cache(Cache),
-    cached_result_paths(Targets, Method, Abstract, Graph, Cache, _, Items).
-
-cached_result_paths([], _, _, _, Cache, Cache, []).
-cached_result_paths([Target|T], Method, Abstract, Graph, CacheIn, CacheOut, [Pair|Pairs]) :-
-    target(Target, URI, _Score),
-    (   cached_search_path(Method, URI, Graph, CacheIn, CacheTmp, Path0),
-	debug(spath, 'Abstract: ~p', [Abstract]),
-	abstract_path(Abstract, Path0, Path)
-    ->  Pair = Path-(Target-Path0)
-    ;   Pair = other-Target
-    ),
-    cached_result_paths(T, Method, Abstract, Graph, CacheTmp, CacheOut, Pairs).
-
-
-%%	abstract_path(+Type, +Path, -Abstract) is det.
-%
-%	* Type = path
-%	Only abstract target.
-%
-%       * Type = spath
-%       abstract full path to schema level
-
-abstract_path(path, [R|Rest0], Path) :-
-    iface_abstract_class(R, Class), !,
-    strip_rdf_value([Class|Rest0], Path0),
-    partial_schema_path(Path0, Path),
-    debug(spath, 'Should not happen PATH: ~p', [Path]).
-
-abstract_path(spath, Path, SPath) :- !,
-    (Path = [R]
-    -> iface_abstract_class(R, Class),
-    SPath = [Class]
-    ; strip_alignment(Path, Path1),
-    schema_path(Path1, SPath0),
-    canonical_path(SPath0, SPath)
-    ),
-    debug(spath, 'schema level path: ~p', [SPath]).
-
-%%	cluster_select(+Clusters, +Start, +End, -ReducedClusters)
-%
-%	Reduced Clusers only contains the items in Cluster starting at
-%	Start and ending at End.
-cluster_select([], _, _, []).
-cluster_select([C-Elems|T], Start, End, [C-Reduced|Rest]) :-
-    elem_select(Elems, Start, End, Reduced),
-    cluster_select(T, Start, End, Rest).
-
-%%	elem_select(+List, +Start, +End, -SubList)
-%
-%	SubList contains the elements from List starting at Start
-%	element up to the End element.
-elem_select(Items, Start, End , Items) :-
-	Start > End, !.
-elem_select(Items, 0, End, Selected) :- !,
-    length(Items, Total),
-    (   Total =< End
-    ->  Selected = Items
-    ;   length(Selected, End),
-	append(Selected, _, Items)
-    ).
-elem_select(Items, Start, End, Selected) :-
-    length(Items, Total),
-    length(L0, Start),
-    append(L0, Rest, Items),
-    (   End >= Total
-    ->  Selected = Rest
-    ;   Length is End - Start,
-	length(Selected, Length),
-	append(Selected, _, Rest)
-    ).
-
-%%	target(+Target, -URI, -Score).
-%
-%	Split up target
-target(Score-URI, URI, Score) :- !.
-target(URI, URI, 1).
-
-/***************************************************
-* enrichment
-***************************************************/
-enrich(clusters(Clusters), clusters(EnrichedClusters), Options) :-
-    enrich_clusters(Clusters, EnrichedClusters, Options).
-
-%%	enrich_clusters(+Clusters, -EnrichedClusters, +Options)
-%
-%	Enrich the clusters with info from the rdf store.
-enrich_clusters([],[],_Options).
-enrich_clusters([Cluster|Clusters], [PrettyPath - EnrichedItems|EnrichedClusters], Options) :-
-    cluster_info(Cluster, Path, ClusterItems),
-    prettify_path(Path, PrettyPath),
-    debug(enrich, 'Enrich Cluster: ~p', [ClusterItems]),
-    enrich_items(ClusterItems, EnrichedItems),
-    enrich_clusters(Clusters, EnrichedClusters, Options).
-
-%%	prettify_path(+Path, -PrettyPath)
-%
-%	Add the label to uris in the path.
-prettify_path([], []).
-prettify_path([Uri|Path], [step(Uri,Label)|PrettyPath]) :-
-    rdf_display_label(Uri, _, Label),
-    prettify_path(Path, PrettyPath).
-
-%%	enrich_items(+Items, -EnrichedItems)
-%
-%	Add a url of the thumbnail, a link to the resultpage and the
-%	title to an item.
-enrich_items([], []).
-enrich_items([_Score-Uri-_List|Results], [item(Uri,ThumbnailUrl,Link,Title)|EnrichedResults]) :-
-    thumbnail_url(Uri, ThumbnailUrl),
-    get_short_title(Uri, 36, Title),
-    concat('item?uri=', Uri, PartLink),
-    http_absolute_location(root(PartLink), Link, []),
-    debug(enrich_item, 'Uri: ~p ThumbnailUrl: ~p Link: ~p Title: ~p',
-	  [Uri,ThumbnailUrl,Link,Title]),
-    enrich_items(Results, EnrichedResults).
-
-:- multifile cliopatria:thumbnail_url/2.
-
-%%	thumbnail_url(+Uri, -ImageUrl)
-%
-%	* Check if image is present, if so, return request url.
-%	* If the image is not present, check if present at url.
-%	* If not present, but a isShownBy present in database, remove
-%	isShownBy triple.
-%       * If not present in cache, database and at url, send image stub.
-thumbnail_url(Uri, ImageUrl) :-
-    cliopatria:thumbnail_url(Uri, ImageUrl),
-    !.
-
-thumbnail_url(Uri, ImageUrl) :-
-    rdf(Aggregation, edm:aggregatedCHO, Uri),
-    rdf(Aggregation, edm:isShownBy, Image),
-    url_cached(Image, file(_)),
-    !,
-    concat('cache/fit?uri=', Image, RequestUrl),
-    http_absolute_location(root(RequestUrl), ImageUrl, []).
-
-thumbnail_url(Uri, ImageUrl) :-
-    rdf(Aggregation, edm:aggregatedCHO, Uri),
-    rdf(Aggregation, edm:isShownBy, Image),
-    https_header_response(Image, Status),
-    Status == 200,
-    !,
-    concat('cache/fit?uri=', Image, RequestUrl),
-    http_absolute_location(root(RequestUrl), ImageUrl, []).
-
-thumbnail_url(Uri, Stub) :-
-    rdf(Aggregation, edm:aggregatedCHO, Uri),
-    rdf(Aggregation, edm:isShownBy, Image),
-    !,
-    rdf_retractall(Uri, rma:imageURL, Image),
-    http_absolute_location(img('/stub.png'), Stub, []).
-
-thumbnail_url(_, Stub) :- http_absolute_location(img('/stub.png'), Stub, []).
-
-%%	https_header_response(+URL, -Status)
-%
-%	Return the response header of input URL.
-https_header_response(URL, Status) :-
-    http_open(URL, In,
-	  [method(head),
-	   status_code(Status),
-	   cert_verify_hook(ssl_verify)
-	  ]),
-    close(In).
-
-:- public ssl_verify/5.
+%	Generate results page.
+results(Request) :-
+    get_parameters(Request, Options),
+    reply_page(results, Options).
 
-%%	ssl_verify(+SSL, +ProblemCert, +AllCerts, +FirstCert, +Error)
+%%	restult(+Request) is det.
 %
-%	Currently we accept  all  certificates.
-ssl_verify(_SSL,
-	   _ProblemCertificate, _AllCertificates, _FirstCertificate,
-	   _Error).
+%	Generate a page showing a result with its metadata.
+item(Request) :-
+    get_parameters(Request, Options),
+    reply_page(result, Options).
 
-%%	get_short_title(+Uri, +DesiredLength, -Title)
+%%	about(+Request) is det.
 %
-%	Returns a title which is shorter or equal the desired length.
-%	Returns the URI if no title is found.
-get_short_title(Uri, DesiredLength, Title) :-
-    rdf(Uri, dc:title, literal(lang(_,Title))),
-    atom_length(Title, CurrentLenght),
-    CurrentLenght =< DesiredLength,
-    !.
-get_short_title(Uri, DesiredLength, Result) :-
-    rdf(Uri, dc:title, literal(lang(_,Title))),
-    atom_chars(Title, List),
-    shorten_list(List, DesiredLength, ShortList),
-    atom_chars(ShortTitle, ShortList),
-    atom_concat(ShortTitle, '...', Result),
-    !.
-get_short_title(Uri, _, Uri).
+%	Generate about page.
+about(Request) :-
+    get_parameters(Request, Options),
+    reply_page(about, Options).
 
-%%	shorten_list(+List, +DesiredLength, -ShortList) is det.
+%%	get_parameters(+Request, -Options)
 %
-%	Shorten a list to the desired length.
-shorten_list(List, Length, ShortList) :-
-    shorten_list(List, Length, 0, ShortList).
-shorten_list([],_,_,[]) :- !.
-shorten_list(_,NrResults,NrResults,[]).
-shorten_list([H|T], Length, N, [H|ShortList]) :-
-    NNew is N + 1,
-    shorten_list(T, Length, NNew, ShortList).
+%	Retrieves an option list of parameters from the url.
+get_parameters(Request, Options) :-
+    http_parameters(Request,
+	[query(Query, [description('Entered Query'), optional(true)]),
+	 uri(URI, [description('URI of the item'), optional(true)])
+	]),
+    Options = [query(Query), uri(URI)].
+
+%%	reply_page(+Page, +Options)
+%
+%	Replies the html page corresponding to the type of page and
+%	Request.
+reply_page(Page, Options) :-
+    setting(search:ui, UI),
+    rdf(UI, ui:iconLocation, literal(IconName)),
+    http_absolute_location(icons(IconName), Icon, []),
+    html_resource(css('search.css'), [requires([css('bootstrap.min.css')])]),
+    reply_html_page(
+	[
+	\title(Page, Options),
+	link([href(Icon),rel('shortcut icon')]),
+	meta([name('viewport'),content('width=device-width, initial-scale=1.0')])
+    ],
+	[\html_requires(css('search.css')),
+	\navigation_bar(Page),
+	\scripts(Page),
+	\content(Page, Options)
+    ]).
diff --git a/lib/cluster_search_ui/settings.pl b/lib/cluster_search_ui/settings.pl
index 701d351..cc08003 100644
--- a/lib/cluster_search_ui/settings.pl
+++ b/lib/cluster_search_ui/settings.pl
@@ -15,9 +15,5 @@
 	   'Setting indicating the level of enrichment of results.').
 :- setting(search:ui, uri, rui:rijksmuseumUI,
 	   'Default URI defining the UI for search').
-:- setting(search:graphSearchCache, boolean, true,
-	   'Cache graph search results').
-:- setting(search:graphSearchCacheSize, nonneg, 50,
-	   'Maximum searches kept in cache (0 is unbound)').
 :- setting(search:annotate, boolean, false,
 	   'Indicate the possibility of annotating search result.').
diff --git a/lib/cluster_search_ui/web_ui_dcg.pl b/lib/cluster_search_ui/web_ui_dcg.pl
index 5842f50..602ee0b 100644
--- a/lib/cluster_search_ui/web_ui_dcg.pl
+++ b/lib/cluster_search_ui/web_ui_dcg.pl
@@ -5,17 +5,15 @@
 	      navigation_bar/3
 	  ]).
 
+:- use_module(library(cluster_search_ui/settings)).
+:- use_module(applications(annotation)).
 :- use_module(library(http/html_write)).
 :- use_module(library(http/http_path)).
-:- use_module(library(http/http_path)).
 :- use_module(library(http/url_cache)).
 :- use_module(library(http/http_open)).
-:- use_module(library('http/http_dispatch')).
+:- use_module(library(http/http_dispatch)).
 :- use_module(library(semweb/rdf_db)).
-:- use_module(library(cluster_search/settings)).
 :- use_module(cliopatria(components/label)).
-:- use_module(library(cluster_search/search_statistics)).
-:- use_module(applications(annotation)).
 
 
 %%	content(+Type, +Options)
@@ -62,46 +60,6 @@ content(about, _) -->
 	  </div>
 	 |}).
 
-content(analytics, _) -->
-    {debug(analytics, 'Querying for statistics.', []),
-     get_dataset_statistics_minimal(DatasetStatistics),
-     %DatasetStatistics = [dataset_statistics(rma, 'Rijksmuseum Collection', [['stub', 36]])],
-     %http_absolute_location(analysis('analysis_results.csv'), AnalysisCSV, []),
-     %concat('areaChart("', AnalysisCSV, FunctionArea0),
-     %concat(FunctionArea0, '");', FunctionArea),
-     %concat('barChart("', AnalysisCSV, FunctionBar0),
-     %concat(FunctionBar0, '");', FunctionBar),
-     debug(analytics, 'The statistics: ~p', [DatasetStatistics])
-    },
-    html([div(class('container-fluid'),
-	 div(class('row'),
-	     [div(class('col-sm-3 col-md-2 sidebar'),
-		 \navigation_analytics),
-	     div(['data-spy'('scroll'), 'data-target'('.sidebar'), class('col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 col-md-8 col-md-offset-2')],
-		 [div([h1('Statistics'),
-		       p(class('lead'),'Get (some) insight in the loaded collection.')]),
-		 %div(id('query-overview'),
-		  %    [a([class('anchor'), id('query-overview-anchor')],''),
-		   %    h2('Query Overview')]),
-		 %div(id('query-matches'),
-		 %    [a([class('anchor'), id('query-matches-anchor')],''),
-		 %     h2('Query Matches')]),
-		 %div(id('analytics-test'),
-		 %    [a([class('anchor'), id('analytics-test-anchor')],''),
-		 %     h2('Analytics Test'),
-		 %     \analytics_html]),
-		 div(id('dataset-statistics'),
-		     [a([class('anchor'), id('dataset-statistics-anchor')],''),
-		      h2('Dataset Statistics'),
-		      \dataset_statistics(DatasetStatistics)])
-		 ])
-	     ])),
-	 %script(src('https://apis.google.com/js/client.js?onload=handleClientLoad'), ''),
-	 \load_javascript(analytics)]).
-	 %script(FunctionArea),
-	 %script(FunctionBar)]).
-     %html([div(id('results'),''),script('analytics();')]).
-
 content(results, Options) -->
     results_page(cluster, Options).
 
@@ -123,14 +81,6 @@ get_annotation_options(Uri, AnnotationOptions) :-
 
 get_image_options(Uri, ImageUrl) :-
     image_url(Uri, ImageUrl).
-%analytics_html -->
-%    html({|html||
-%    <!-- The 2 Buttons for the user to interact with -->
-%    <button id="authorize-button" style="visibility:
-%    hidden">Authorize</button><br/>
-%    <button id="make-api-call-button" style="visibility: hidden">Get Visits</button>	     |}).
-%
-
 
 %%	get_carousel_items(-CarouselItems)
 %
@@ -248,40 +198,24 @@ query_title(Uri, Title) :-
 scripts(front) -->
     html([\load_javascript(jquery),
 	  \load_javascript(bootstrap),
-	  \load_javascript(type_ahead),
-	  \load_javascript(search),
-	  \load_javascript(google_analytics)]).
+	  \load_javascript(search)]).
 
 scripts(results) -->
     html([\load_javascript(jquery),
 	  \load_javascript(bootstrap),
-	  \load_javascript(type_ahead),
 	  \load_javascript(search),
 	  \load_javascript(pagination),
-	  \load_javascript(thumbnail),
-          \load_javascript(google_analytics)]).
+	  \load_javascript(thumbnail)]).
 
 scripts(result) -->
     html([\load_javascript(jquery),
 	  \load_javascript(bootstrap),
-	  \load_javascript(type_ahead),
-	  \load_javascript(search),
-	  \load_javascript(google_analytics)]).
+	  \load_javascript(search)]).
 
 scripts(about) -->
     html([\load_javascript(jquery),
 	  \load_javascript(bootstrap),
-	  \load_javascript(type_ahead),
-	  \load_javascript(search),
-	  \load_javascript(google_analytics)]).
-
-scripts(analytics) -->
-    html([\load_javascript(jquery),
-	  \load_javascript(bootstrap),
-	  \load_javascript(d3js),
-	  \load_javascript(type_ahead),
-	  \load_javascript(search),
-	  \load_javascript(google_analytics)]).
+	  \load_javascript(search)]).
 
 %%	load_javascript(+Script)
 %
@@ -291,11 +225,6 @@ load_javascript(jquery) -->
 load_javascript(bootstrap) -->
     {http_absolute_location(js('bootstrap.min.js'), JavaScriptBootstrap, [])},
     html(script(src(JavaScriptBootstrap),'')).
-load_javascript(d3js) -->
-    html(script(src('http://d3js.org/d3.v3.js'),'')).
-load_javascript(type_ahead) -->
-    {http_absolute_location(js('typeahead.min.js'), JavaScriptTypeahead, [])},
-    html(script(src(JavaScriptTypeahead),'')).
 load_javascript(search) -->
     {http_absolute_location(js('search.js'), JavaScriptSearch, [])},
     html(script(src(JavaScriptSearch),'')).
@@ -305,25 +234,18 @@ load_javascript(pagination) -->
 load_javascript(thumbnail) -->
     {http_absolute_location(js('thumbnail.js'), JavaScriptThumbnail, [])},
     html(script(src(JavaScriptThumbnail),'')).
-load_javascript(google_analytics) -->
-    {http_absolute_location(js('google_analytics.js'), JavaScriptGoogleAnalytics, [])},
-    html(script(src(JavaScriptGoogleAnalytics),'')).
-load_javascript(analytics) -->
-    {http_absolute_location(js('analytics.js'), JavaScriptAnalytics, [])},
-    html(script(src(JavaScriptAnalytics),'')).
 
 %%	navigation_bar(+Page)
 %
 %	Generates the navigation bar for the given page.
 navigation_bar(front) -->
-    {http_location_by_id(web, HttpWeb),
+    {http_location_by_id(search, HttpWeb),
      http_location_by_id(results, HttpSearch),
      http_location_by_id(about, HttpAbout),
-     http_location_by_id(analytics, HttpAnalytics),
      setting(search:ui, UI),
      rdf(UI, dcterms:title, literal(lang(en, Title)))
     },
-    html({|html(HttpWeb, HttpSearch, HttpAbout, HttpAnalytics, Title)||
+    html({|html(HttpWeb, HttpSearch, HttpAbout, Title)||
 	  <nav class="navbar navbar-fixed-top navbar-inverse" role="navigation">
 	    <div class="navbar-header">
 	      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-sign-collapse">
@@ -334,7 +256,6 @@ navigation_bar(front) -->
 
 	    <div class="collapse navbar-collapse navbar-sign-collapse">
               <ul class="nav navbar-nav navbar-right">
-	        <li><a href="HttpAnalytics">Statistics</a></li>
 	        <li><a href="HttpAbout">About</a></li>
 	      </ul>
 	      <form class="navbar-form" action="HttpSearch" autocomplete="off">
@@ -350,14 +271,13 @@ navigation_bar(front) -->
 	 |}).
 
 navigation_bar(about) -->
-    {http_location_by_id(web, HttpWeb),
+    {http_location_by_id(search, HttpWeb),
      http_location_by_id(results, HttpSearch),
      http_location_by_id(about, HttpAbout),
-     http_location_by_id(analytics, HttpAnalytics),
      setting(search:ui, UI),
      rdf(UI, dcterms:title, literal(lang(en, Title)))
     },
-    html({|html(HttpWeb, HttpSearch, HttpAbout, HttpAnalytics, Title)||
+    html({|html(HttpWeb, HttpSearch, HttpAbout, Title)||
 	  <nav class="navbar navbar-fixed-top navbar-inverse" role="navigation">
 	    <div class="navbar-header">
 	      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-sign-collapse">
@@ -368,7 +288,6 @@ navigation_bar(about) -->
 
 	    <div class="collapse navbar-collapse navbar-sign-collapse">
               <ul class="nav navbar-nav navbar-right">
-	        <li><a href="HttpAnalytics">Statistics</a></li>
 	        <li class="active"><a href="HttpAbout">About</a></li>
 	      </ul>
 	      <form class="navbar-form" action="HttpSearch" autocomplete="off">
@@ -383,53 +302,10 @@ navigation_bar(about) -->
 	  </nav>
 	 |}).
 
-navigation_bar(analytics) -->
-    {http_location_by_id(web, HttpWeb),
-     http_location_by_id(results, HttpSearch),
-     http_location_by_id(about, HttpAbout),
-     http_location_by_id(analytics, HttpAnalytics),
-     setting(search:ui, UI),
-     rdf(UI, dcterms:title, literal(lang(en, Title)))
-    },
-    html({|html(HttpWeb, HttpSearch, HttpAbout, HttpAnalytics, Title)||
-	  <nav class="navbar navbar-fixed-top navbar-inverse" role="navigation">
-	    <div class="navbar-header">
-	      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-sign-collapse">
-	        <span class="icon-bar"></span>
-	      </button>
-	      <a class="navbar-brand" href="HttpWeb">Title</a>
-	    </div>
-
-	    <div class="collapse navbar-collapse navbar-sign-collapse">
-              <ul class="nav navbar-nav navbar-right">
-	        <li class="active"><a href="HttpAnalytics">Statistics</a></li>
-		<li><a href="HttpAbout">About</a></li>
-	      </ul>
-	      <form class="navbar-form" action="HttpSearch" autocomplete="off">
-	        <div class="input-group search-form">
-	          <input type="search" class="form-control typeahead" name="query">
-		  <span class="input-group-btn">
-		    <button type="submit" class="btn btn-default">Search</button>
-		  </span>
-	        </div><!-- /input-group -->
-	      </form>
-	    </div>
-	  </nav>
-	 |}).
-
 
 navigation_bar(results) --> navigation_bar(front).
 navigation_bar(result) --> navigation_bar(front).
 
-navigation_analytics -->
-    html({|html||
-	  <ul class="nav nav-sidebar">
-            <!--<li class="active"><a href="#query-overview-anchor">Query Overview</a></li>-->
-	    <!--<li><a href="#query-matches-anchor">Query Matches</a></li>-->
-	    <li><a href="#dataset-statistics-anchor">Dataset</a></li>
-          </ul>
-	 |}).
-
 %%	metadata(+ListOfPredicateObjectPairs)
 %
 %	Loops through the list of metadata fields
@@ -447,61 +323,6 @@ format_metadata(Predicate, Object) -->
 	 dd(\rdf_link(Object, [resource_format(nslabel)]))
 	]).
 
-%%	dataset_statistics(+Statistics)
-%
-%	Loops through the list of dataset statistics
-dataset_statistics(Statistics) -->
-    html([ul(class('nav nav-tabs'),\navigation_tabs(Statistics)),
-	 div(class('tab-content'),\tab_tables(Statistics))]).
-
-%%	navigation_tabs(+Statistics)
-%
-%	Loops through the list of dataset statistics
-navigation_tabs([First|More]) -->
-    html([\first_tab(First),
-	 \more_tabs(More)]).
-
-first_tab(dataset_statistics(ID, Name, _Statistics)) -->
-    {concat('#', ID, IDRef)},
-    html(li(class('active'), a([href(IDRef), 'data-toggle'('tab')], Name))).
-
-more_tabs([]) --> [].
-more_tabs([dataset_statistics(ID, Name, _Statistics)|T]) -->
-    {concat('#', ID, IDRef)},
-    html(li(a([href(IDRef), 'data-toggle'('tab')], Name))),
-    more_tabs(T).
-
-%%	tab_tables(+Statistics)
-%
-%	Loops through the list of dataset statistics to create the
-%	contents, which are tables.
-tab_tables([First|More]) -->
-    html([\first_tab_pane(First),
-	 \more_tab_panes(More)]).
-
-
-first_tab_pane(dataset_statistics(ID, _Name, Statistics)) -->
-    html(div([class('tab-pane fade in active'),id(ID)],
-	     table(class('table table-striped'),\dataset_rows(Statistics)))).
-
-more_tab_panes([]) --> [].
-more_tab_panes([Dataset|T]) -->
-    html(\tab_pane(Dataset)),
-    more_tab_panes(T).
-
-tab_pane(dataset_statistics(ID, _Name, Statistics)) -->
-    html(div([class('tab-pane fade data-table'),id(ID)],
-	     table(class('table table-striped'),
-		   \dataset_rows(Statistics)))).
-
-%%     dataset_rowd(+Statistics)
-%
-%      Loops through the list of dataset statistics
-dataset_rows([]) --> [].
-dataset_rows([[Property, Value]|T]) -->
-    html([tr([td(Property), td(Value)])]),
-    dataset_rows(T).
-
 %%	results_page(+TypeResults, +Results, +NumberOfResults)
 %
 %	Generates a div were the results are shown.
diff --git a/web/js/analytics.js b/web/js/analytics.js
deleted file mode 100644
index ded8985..0000000
--- a/web/js/analytics.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/* Analytics
-*  Code for sending information to google analytics and calling the analytics api for aggregates.
-*/
-//Sidebar link switching
-$(" .nav-sidebar li a").click(function() {
-	$(" .nav-sidebar li ").removeClass('active');
-	var $parent = $(this).parent();
-	if (!$parent.hasClass('active')) {
-		$parent.addClass('active');
-	}
-});
-
-function barChart(filePath) {
-	var margin = {top: 20, right: 20, bottom: 80, left: 40},
-    width = 960 - margin.left - margin.right,
-    height = 500 - margin.top - margin.bottom;
-
-	var x = d3.scale.ordinal()
-	    .rangeRoundBands([0, width], 0.1);
-	
-	var y = d3.scale.linear()
-	    .range([height, 0]);
-	
-	var xAxis = d3.svg.axis()
-	    .scale(x)
-	    .orient("bottom");
-	
-	var yAxis = d3.svg.axis()
-	    .scale(y)
-	    .orient("left")
-	    .ticks(10);
-	
-	var svg = d3.select("#query-matches").append("svg")
-	    .attr("width", width + margin.left + margin.right)
-	    .attr("height", height + margin.top + margin.bottom)
-	  .append("g")
-	    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
-	
-	d3.csv(filePath, type, function(error, data) {
-	  var start = 0;
-	  var stop = 50;
-	  data = data.slice(start,stop);
-	  
-	  x.domain(data.map(function(d) { return d.query; }));
-	  y.domain([0, d3.max(data, function(d) { return d.number; })]);
-	
-	  svg.append("g")
-	      .attr("class", "x axis bar-axis")
-	      .attr("transform", "translate(0," + height + ")")
-	      .call(xAxis)
-	      .selectAll("text")  
-	            .style("text-anchor", "end")
-	            .attr("dx", "-.8em")
-	            .attr("dy", ".15em")
-	            .attr("transform", function(d) {
-	                return "rotate(-65)" 
-	                });
-	
-	  svg.append("g")
-	      .attr("class", "y axis")
-	      .call(yAxis)
-	    .append("text")
-	      .attr("transform", "rotate(-90)")
-	      .attr("y", 6)
-	      .attr("dy", ".71em")
-	      .style("text-anchor", "end")
-	      .text("Number of times the query is used at the RMA site");
-	  
-	  //function (d) { return "bar " + d.direct_match };
-	  function match_class(direct_match, direct_match_ic) { 
-	  	if(direct_match_ic == "true") {
-	  		return "bar direct_match_ic";
-	  	} else if (direct_match == "true") {
-	  		return "bar direct_match";
-	  	}
-	  	return "bar no_match";
-	  }
-		
-	
-	  svg.selectAll(".bar")
-	      .data(data)
-	    .enter().append("rect")
-	      .attr("class", function(d) { return match_class(d.direct_match, d.direct_match_ic); })
-	      .attr("x", function(d) { return x(d.query); })
-	      .attr("width", x.rangeBand())
-	      .attr("y", function(d) { return y(d.number); })
-	      .attr("height", function(d) { return height - y(d.number); });
-	
-	});
-	
-	
-	function type(d) {
-	  d.number = +d.number;
-	  d.direct_match
-	  return d;
-	}
-}
-
-function areaChart(filePath) {
-	var margin = {top: 20, right: 20, bottom: 30, left: 50},
-	    width = 1024 - margin.left - margin.right,
-	    height = 600 - margin.top - margin.bottom;
-
-	var x = d3.scale.linear()
-	    .range([0, width]);
-
-	var y = d3.scale.linear()
-	    .range([height, 0]);
-
-	var xAxis = d3.svg.axis()
-	    .scale(x)
-	    .orient("bottom");
-
-	var yAxis = d3.svg.axis()
-	    .scale(y)
-	    .orient("left");
-
-	var area = d3.svg.area()
-	    .x(function(d) { return x(d.index); })
-	    .y0(height)
-	    .y1(function(d) { return y(d.number); });
-
-	var svg = d3.select("#query-overview").append("svg")
-	    .attr("width", width + margin.left + margin.right)
-	    .attr("height", height + margin.top + margin.bottom)
-	  .append("g")
-	    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
-
-	d3.csv(filePath, function(error, data) {
-		index = 0;
-		data.forEach(function(d) {
-	        d.number = +d.number;
-	        d.index = index;
-	        index++;
-	    });
-	    
-		var start = 0;
-		var stop = 2000;
-		data = data.slice(start,stop);
-		
-		x.domain([0, data.length]);
-	    y.domain([0, d3.max(data, function(d) { return d.number; })]);
-	    
-	    svg.append("path")
-	    .datum(data)
-	    .attr("class", "area")
-	    .attr("d", area);
-	    
-	    svg.append("g")
-	    .attr("class", "x axis")
-	    .attr("transform", "translate(0," + height + ")")
-	    .call(xAxis);
-	    
-	    svg.append("g")
-	    .attr("class", "y axis")
-	    .call(yAxis)
-	  .append("text")
-	    .attr("transform", "rotate(-90)")
-	    .attr("y", 6)
-	    .attr("dy", ".71em")
-	    .style("text-anchor", "end")
-	    .text("Number of queries");
-	});
-}
\ No newline at end of file
diff --git a/web/js/google_analytics.js b/web/js/google_analytics.js
deleted file mode 100644
index 1c07e70..0000000
--- a/web/js/google_analytics.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Analytics
-*  Code for sending information to google analytics and calling the analytics api for aggregates.
-*/  
-
-// Send information to Google Analytics
-//(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
-//	(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
-//	m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
-//})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
-//
-//ga('create', 'UA-47334744-1', 'vu.nl');
-//ga('send', 'pageview');
\ No newline at end of file
diff --git a/web/js/typeahead.min.js b/web/js/typeahead.min.js
deleted file mode 100644
index c085f8a..0000000
--- a/web/js/typeahead.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * typeahead.js 0.9.3
- * https://github.com/twitter/typeahead
- * Copyright 2013 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-!function(a){var b="0.9.3",c={isMsie:function(){var a=/(msie) ([\w.]+)/i.exec(navigator.userAgent);return a?parseInt(a[2],10):!1},isBlankString:function(a){return!a||/^\s*$/.test(a)},escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(a){return"string"==typeof a},isNumber:function(a){return"number"==typeof a},isArray:a.isArray,isFunction:a.isFunction,isObject:a.isPlainObject,isUndefined:function(a){return"undefined"==typeof a},bind:a.proxy,bindAll:function(b){var c;for(var d in b)a.isFunction(c=b[d])&&(b[d]=a.proxy(c,b))},indexOf:function(a,b){for(var c=0;c<a.length;c++)if(a[c]===b)return c;return-1},each:a.each,map:a.map,filter:a.grep,every:function(b,c){var d=!0;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?void 0:!1}),!!d):d},some:function(b,c){var d=!1;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?!1:void 0}),!!d):d},mixin:a.extend,getUniqueId:function(){var a=0;return function(){return a++}}(),defer:function(a){setTimeout(a,0)},debounce:function(a,b,c){var d,e;return function(){var f,g,h=this,i=arguments;return f=function(){d=null,c||(e=a.apply(h,i))},g=c&&!d,clearTimeout(d),d=setTimeout(f,b),g&&(e=a.apply(h,i)),e}},throttle:function(a,b){var c,d,e,f,g,h;return g=0,h=function(){g=new Date,e=null,f=a.apply(c,d)},function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,0>=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},tokenizeQuery:function(b){return a.trim(b).toLowerCase().split(/[\s]+/)},tokenizeText:function(b){return a.trim(b).toLowerCase().split(/[\s\-_]+/)},getProtocol:function(){return location.protocol},noop:function(){}},d=function(){var a=/\s+/;return{on:function(b,c){var d;if(!c)return this;for(this._callbacks=this._callbacks||{},b=b.split(a);d=b.shift();)this._callbacks[d]=this._callbacks[d]||[],this._callbacks[d].push(c);return this},trigger:function(b,c){var d,e;if(!this._callbacks)return this;for(b=b.split(a);d=b.shift();)if(e=this._callbacks[d])for(var f=0;f<e.length;f+=1)e[f].call(this,{type:d,data:c});return this}}}(),e=function(){function b(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el)}var d="typeahead:";return c.mixin(b.prototype,{trigger:function(a){var b=[].slice.call(arguments,1);this.$el.trigger(d+a,b)}}),b}(),f=function(){function a(a){this.prefix=["__",a,"__"].join(""),this.ttlKey="__ttl__",this.keyMatcher=new RegExp("^"+this.prefix)}function b(){return(new Date).getTime()}function d(a){return JSON.stringify(c.isUndefined(a)?null:a)}function e(a){return JSON.parse(a)}var f,g;try{f=window.localStorage,f.setItem("~~~","!"),f.removeItem("~~~")}catch(h){f=null}return g=f&&window.JSON?{_prefix:function(a){return this.prefix+a},_ttlKey:function(a){return this._prefix(a)+this.ttlKey},get:function(a){return this.isExpired(a)&&this.remove(a),e(f.getItem(this._prefix(a)))},set:function(a,e,g){return c.isNumber(g)?f.setItem(this._ttlKey(a),d(b()+g)):f.removeItem(this._ttlKey(a)),f.setItem(this._prefix(a),d(e))},remove:function(a){return f.removeItem(this._ttlKey(a)),f.removeItem(this._prefix(a)),this},clear:function(){var a,b,c=[],d=f.length;for(a=0;d>a;a++)(b=f.key(a)).match(this.keyMatcher)&&c.push(b.replace(this.keyMatcher,""));for(a=c.length;a--;)this.remove(c[a]);return this},isExpired:function(a){var d=e(f.getItem(this._ttlKey(a)));return c.isNumber(d)&&b()>d?!0:!1}}:{get:c.noop,set:c.noop,remove:c.noop,clear:c.noop,isExpired:c.noop},c.mixin(a.prototype,g),a}(),g=function(){function a(a){c.bindAll(this),a=a||{},this.sizeLimit=a.sizeLimit||10,this.cache={},this.cachedKeysByAge=[]}return c.mixin(a.prototype,{get:function(a){return this.cache[a]},set:function(a,b){var c;this.cachedKeysByAge.length===this.sizeLimit&&(c=this.cachedKeysByAge.shift(),delete this.cache[c]),this.cache[a]=b,this.cachedKeysByAge.push(a)}}),a}(),h=function(){function b(a){c.bindAll(this),a=c.isString(a)?{url:a}:a,i=i||new g,h=c.isNumber(a.maxParallelRequests)?a.maxParallelRequests:h||6,this.url=a.url,this.wildcard=a.wildcard||"%QUERY",this.filter=a.filter,this.replace=a.replace,this.ajaxSettings={type:"get",cache:a.cache,timeout:a.timeout,dataType:a.dataType||"json",beforeSend:a.beforeSend},this._get=(/^throttle$/i.test(a.rateLimitFn)?c.throttle:c.debounce)(this._get,a.rateLimitWait||300)}function d(){j++}function e(){j--}function f(){return h>j}var h,i,j=0,k={};return c.mixin(b.prototype,{_get:function(a,b){function c(c){var e=d.filter?d.filter(c):c;b&&b(e),i.set(a,c)}var d=this;f()?this._sendRequest(a).done(c):this.onDeckRequestArgs=[].slice.call(arguments,0)},_sendRequest:function(b){function c(){e(),k[b]=null,f.onDeckRequestArgs&&(f._get.apply(f,f.onDeckRequestArgs),f.onDeckRequestArgs=null)}var f=this,g=k[b];return g||(d(),g=k[b]=a.ajax(b,this.ajaxSettings).always(c)),g},get:function(a,b){var d,e,f=this,g=encodeURIComponent(a||"");return b=b||c.noop,d=this.replace?this.replace(this.url,g):this.url.replace(this.wildcard,g),(e=i.get(d))?c.defer(function(){b(f.filter?f.filter(e):e)}):this._get(d,b),!!e}}),b}(),i=function(){function d(b){c.bindAll(this),c.isString(b.template)&&!b.engine&&a.error("no template engine specified"),b.local||b.prefetch||b.remote||a.error("one of local, prefetch, or remote is required"),this.name=b.name||c.getUniqueId(),this.limit=b.limit||5,this.minLength=b.minLength||1,this.header=b.header,this.footer=b.footer,this.valueKey=b.valueKey||"value",this.template=e(b.template,b.engine,this.valueKey),this.local=b.local,this.prefetch=b.prefetch,this.remote=b.remote,this.itemHash={},this.adjacencyList={},this.storage=b.name?new f(b.name):null}function e(a,b,d){var e,f;return c.isFunction(a)?e=a:c.isString(a)?(f=b.compile(a),e=c.bind(f.render,f)):e=function(a){return"<p>"+a[d]+"</p>"},e}var g={thumbprint:"thumbprint",protocol:"protocol",itemHash:"itemHash",adjacencyList:"adjacencyList"};return c.mixin(d.prototype,{_processLocalData:function(a){this._mergeProcessedData(this._processData(a))},_loadPrefetchData:function(d){function e(a){var b=d.filter?d.filter(a):a,e=m._processData(b),f=e.itemHash,h=e.adjacencyList;m.storage&&(m.storage.set(g.itemHash,f,d.ttl),m.storage.set(g.adjacencyList,h,d.ttl),m.storage.set(g.thumbprint,n,d.ttl),m.storage.set(g.protocol,c.getProtocol(),d.ttl)),m._mergeProcessedData(e)}var f,h,i,j,k,l,m=this,n=b+(d.thumbprint||"");return this.storage&&(f=this.storage.get(g.thumbprint),h=this.storage.get(g.protocol),i=this.storage.get(g.itemHash),j=this.storage.get(g.adjacencyList)),k=f!==n||h!==c.getProtocol(),d=c.isString(d)?{url:d}:d,d.ttl=c.isNumber(d.ttl)?d.ttl:864e5,i&&j&&!k?(this._mergeProcessedData({itemHash:i,adjacencyList:j}),l=a.Deferred().resolve()):l=a.getJSON(d.url).done(e),l},_transformDatum:function(a){var b=c.isString(a)?a:a[this.valueKey],d=a.tokens||c.tokenizeText(b),e={value:b,tokens:d};return c.isString(a)?(e.datum={},e.datum[this.valueKey]=a):e.datum=a,e.tokens=c.filter(e.tokens,function(a){return!c.isBlankString(a)}),e.tokens=c.map(e.tokens,function(a){return a.toLowerCase()}),e},_processData:function(a){var b=this,d={},e={};return c.each(a,function(a,f){var g=b._transformDatum(f),h=c.getUniqueId(g.value);d[h]=g,c.each(g.tokens,function(a,b){var d=b.charAt(0),f=e[d]||(e[d]=[h]);!~c.indexOf(f,h)&&f.push(h)})}),{itemHash:d,adjacencyList:e}},_mergeProcessedData:function(a){var b=this;c.mixin(this.itemHash,a.itemHash),c.each(a.adjacencyList,function(a,c){var d=b.adjacencyList[a];b.adjacencyList[a]=d?d.concat(c):c})},_getLocalSuggestions:function(a){var b,d=this,e=[],f=[],g=[];return c.each(a,function(a,b){var d=b.charAt(0);!~c.indexOf(e,d)&&e.push(d)}),c.each(e,function(a,c){var e=d.adjacencyList[c];return e?(f.push(e),(!b||e.length<b.length)&&(b=e),void 0):!1}),f.length<e.length?[]:(c.each(b,function(b,e){var h,i,j=d.itemHash[e];h=c.every(f,function(a){return~c.indexOf(a,e)}),i=h&&c.every(a,function(a){return c.some(j.tokens,function(b){return 0===b.indexOf(a)})}),i&&g.push(j)}),g)},initialize:function(){var b;return this.local&&this._processLocalData(this.local),this.transport=this.remote?new h(this.remote):null,b=this.prefetch?this._loadPrefetchData(this.prefetch):a.Deferred().resolve(),this.local=this.prefetch=this.remote=null,this.initialize=function(){return b},b},getSuggestions:function(a,b){function d(a){f=f.slice(0),c.each(a,function(a,b){var d,e=g._transformDatum(b);return d=c.some(f,function(a){return e.value===a.value}),!d&&f.push(e),f.length<g.limit}),b&&b(f)}var e,f,g=this,h=!1;a.length<this.minLength||(e=c.tokenizeQuery(a),f=this._getLocalSuggestions(e).slice(0,this.limit),f.length<this.limit&&this.transport&&(h=this.transport.get(a,d)),!h&&b&&b(f))}}),d}(),j=function(){function b(b){var d=this;c.bindAll(this),this.specialKeyCodeMap={9:"tab",27:"esc",37:"left",39:"right",13:"enter",38:"up",40:"down"},this.$hint=a(b.hint),this.$input=a(b.input).on("blur.tt",this._handleBlur).on("focus.tt",this._handleFocus).on("keydown.tt",this._handleSpecialKeyEvent),c.isMsie()?this.$input.on("keydown.tt keypress.tt cut.tt paste.tt",function(a){d.specialKeyCodeMap[a.which||a.keyCode]||c.defer(d._compareQueryToInputValue)}):this.$input.on("input.tt",this._compareQueryToInputValue),this.query=this.$input.val(),this.$overflowHelper=e(this.$input)}function e(b){return a("<span></span>").css({position:"absolute",left:"-9999px",visibility:"hidden",whiteSpace:"nowrap",fontFamily:b.css("font-family"),fontSize:b.css("font-size"),fontStyle:b.css("font-style"),fontVariant:b.css("font-variant"),fontWeight:b.css("font-weight"),wordSpacing:b.css("word-spacing"),letterSpacing:b.css("letter-spacing"),textIndent:b.css("text-indent"),textRendering:b.css("text-rendering"),textTransform:b.css("text-transform")}).insertAfter(b)}function f(a,b){return a=(a||"").replace(/^\s*/g,"").replace(/\s{2,}/g," "),b=(b||"").replace(/^\s*/g,"").replace(/\s{2,}/g," "),a===b}return c.mixin(b.prototype,d,{_handleFocus:function(){this.trigger("focused")},_handleBlur:function(){this.trigger("blured")},_handleSpecialKeyEvent:function(a){var b=this.specialKeyCodeMap[a.which||a.keyCode];b&&this.trigger(b+"Keyed",a)},_compareQueryToInputValue:function(){var a=this.getInputValue(),b=f(this.query,a),c=b?this.query.length!==a.length:!1;c?this.trigger("whitespaceChanged",{value:this.query}):b||this.trigger("queryChanged",{value:this.query=a})},destroy:function(){this.$hint.off(".tt"),this.$input.off(".tt"),this.$hint=this.$input=this.$overflowHelper=null},focus:function(){this.$input.focus()},blur:function(){this.$input.blur()},getQuery:function(){return this.query},setQuery:function(a){this.query=a},getInputValue:function(){return this.$input.val()},setInputValue:function(a,b){this.$input.val(a),!b&&this._compareQueryToInputValue()},getHintValue:function(){return this.$hint.val()},setHintValue:function(a){this.$hint.val(a)},getLanguageDirection:function(){return(this.$input.css("direction")||"ltr").toLowerCase()},isOverflow:function(){return this.$overflowHelper.text(this.getInputValue()),this.$overflowHelper.width()>this.$input.width()},isCursorAtEnd:function(){var a,b=this.$input.val().length,d=this.$input[0].selectionStart;return c.isNumber(d)?d===b:document.selection?(a=document.selection.createRange(),a.moveStart("character",-b),b===a.text.length):!0}}),b}(),k=function(){function b(b){c.bindAll(this),this.isOpen=!1,this.isEmpty=!0,this.isMouseOverDropdown=!1,this.$menu=a(b.menu).on("mouseenter.tt",this._handleMouseenter).on("mouseleave.tt",this._handleMouseleave).on("click.tt",".tt-suggestion",this._handleSelection).on("mouseover.tt",".tt-suggestion",this._handleMouseover)}function e(a){return a.data("suggestion")}var f={suggestionsList:'<span class="tt-suggestions"></span>'},g={suggestionsList:{display:"block"},suggestion:{whiteSpace:"nowrap",cursor:"pointer"},suggestionChild:{whiteSpace:"normal"}};return c.mixin(b.prototype,d,{_handleMouseenter:function(){this.isMouseOverDropdown=!0},_handleMouseleave:function(){this.isMouseOverDropdown=!1},_handleMouseover:function(b){var c=a(b.currentTarget);this._getSuggestions().removeClass("tt-is-under-cursor"),c.addClass("tt-is-under-cursor")},_handleSelection:function(b){var c=a(b.currentTarget);this.trigger("suggestionSelected",e(c))},_show:function(){this.$menu.css("display","block")},_hide:function(){this.$menu.hide()},_moveCursor:function(a){var b,c,d,f;if(this.isVisible()){if(b=this._getSuggestions(),c=b.filter(".tt-is-under-cursor"),c.removeClass("tt-is-under-cursor"),d=b.index(c)+a,d=(d+1)%(b.length+1)-1,-1===d)return this.trigger("cursorRemoved"),void 0;-1>d&&(d=b.length-1),f=b.eq(d).addClass("tt-is-under-cursor"),this._ensureVisibility(f),this.trigger("cursorMoved",e(f))}},_getSuggestions:function(){return this.$menu.find(".tt-suggestions > .tt-suggestion")},_ensureVisibility:function(a){var b=this.$menu.height()+parseInt(this.$menu.css("paddingTop"),10)+parseInt(this.$menu.css("paddingBottom"),10),c=this.$menu.scrollTop(),d=a.position().top,e=d+a.outerHeight(!0);0>d?this.$menu.scrollTop(c+d):e>b&&this.$menu.scrollTop(c+(e-b))},destroy:function(){this.$menu.off(".tt"),this.$menu=null},isVisible:function(){return this.isOpen&&!this.isEmpty},closeUnlessMouseIsOverDropdown:function(){this.isMouseOverDropdown||this.close()},close:function(){this.isOpen&&(this.isOpen=!1,this.isMouseOverDropdown=!1,this._hide(),this.$menu.find(".tt-suggestions > .tt-suggestion").removeClass("tt-is-under-cursor"),this.trigger("closed"))},open:function(){this.isOpen||(this.isOpen=!0,!this.isEmpty&&this._show(),this.trigger("opened"))},setLanguageDirection:function(a){var b={left:"0",right:"auto"},c={left:"auto",right:" 0"};"ltr"===a?this.$menu.css(b):this.$menu.css(c)},moveCursorUp:function(){this._moveCursor(-1)},moveCursorDown:function(){this._moveCursor(1)},getSuggestionUnderCursor:function(){var a=this._getSuggestions().filter(".tt-is-under-cursor").first();return a.length>0?e(a):null},getFirstSuggestion:function(){var a=this._getSuggestions().first();return a.length>0?e(a):null},renderSuggestions:function(b,d){var e,h,i,j,k,l="tt-dataset-"+b.name,m='<div class="tt-suggestion">%body</div>',n=this.$menu.find("."+l);0===n.length&&(h=a(f.suggestionsList).css(g.suggestionsList),n=a("<div></div>").addClass(l).append(b.header).append(h).append(b.footer).appendTo(this.$menu)),d.length>0?(this.isEmpty=!1,this.isOpen&&this._show(),i=document.createElement("div"),j=document.createDocumentFragment(),c.each(d,function(c,d){d.dataset=b.name,e=b.template(d.datum),i.innerHTML=m.replace("%body",e),k=a(i.firstChild).css(g.suggestion).data("suggestion",d),k.children().each(function(){a(this).css(g.suggestionChild)}),j.appendChild(k[0])}),n.show().find(".tt-suggestions").html(j)):this.clearSuggestions(b.name),this.trigger("suggestionsRendered")},clearSuggestions:function(a){var b=a?this.$menu.find(".tt-dataset-"+a):this.$menu.find('[class^="tt-dataset-"]'),c=b.find(".tt-suggestions");b.hide(),c.empty(),0===this._getSuggestions().length&&(this.isEmpty=!0,this._hide())}}),b}(),l=function(){function b(a){var b,d,f;c.bindAll(this),this.$node=e(a.input),this.datasets=a.datasets,this.dir=null,this.eventBus=a.eventBus,b=this.$node.find(".tt-dropdown-menu"),d=this.$node.find(".tt-query"),f=this.$node.find(".tt-hint"),this.dropdownView=new k({menu:b}).on("suggestionSelected",this._handleSelection).on("cursorMoved",this._clearHint).on("cursorMoved",this._setInputValueToSuggestionUnderCursor).on("cursorRemoved",this._setInputValueToQuery).on("cursorRemoved",this._updateHint).on("suggestionsRendered",this._updateHint).on("opened",this._updateHint).on("closed",this._clearHint).on("opened closed",this._propagateEvent),this.inputView=new j({input:d,hint:f}).on("focused",this._openDropdown).on("blured",this._closeDropdown).on("blured",this._setInputValueToQuery).on("enterKeyed tabKeyed",this._handleSelection).on("queryChanged",this._clearHint).on("queryChanged",this._clearSuggestions).on("queryChanged",this._getSuggestions).on("whitespaceChanged",this._updateHint).on("queryChanged whitespaceChanged",this._openDropdown).on("queryChanged whitespaceChanged",this._setLanguageDirection).on("escKeyed",this._closeDropdown).on("escKeyed",this._setInputValueToQuery).on("tabKeyed upKeyed downKeyed",this._managePreventDefault).on("upKeyed downKeyed",this._moveDropdownCursor).on("upKeyed downKeyed",this._openDropdown).on("tabKeyed leftKeyed rightKeyed",this._autocomplete)}function e(b){var c=a(g.wrapper),d=a(g.dropdown),e=a(b),f=a(g.hint);c=c.css(h.wrapper),d=d.css(h.dropdown),f.css(h.hint).css({backgroundAttachment:e.css("background-attachment"),backgroundClip:e.css("background-clip"),backgroundColor:e.css("background-color"),backgroundImage:e.css("background-image"),backgroundOrigin:e.css("background-origin"),backgroundPosition:e.css("background-position"),backgroundRepeat:e.css("background-repeat"),backgroundSize:e.css("background-size")}),e.data("ttAttrs",{dir:e.attr("dir"),autocomplete:e.attr("autocomplete"),spellcheck:e.attr("spellcheck"),style:e.attr("style")}),e.addClass("tt-query").attr({autocomplete:"off",spellcheck:!1}).css(h.query);try{!e.attr("dir")&&e.attr("dir","auto")}catch(i){}return e.wrap(c).parent().prepend(f).append(d)}function f(a){var b=a.find(".tt-query");c.each(b.data("ttAttrs"),function(a,d){c.isUndefined(d)?b.removeAttr(a):b.attr(a,d)}),b.detach().removeData("ttAttrs").removeClass("tt-query").insertAfter(a),a.remove()}var g={wrapper:'<span class="twitter-typeahead"></span>',hint:'<input class="tt-hint" type="text" autocomplete="off" spellcheck="off" disabled>',dropdown:'<span class="tt-dropdown-menu"></span>'},h={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none"},query:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},dropdown:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"}};return c.isMsie()&&c.mixin(h.query,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),c.isMsie()&&c.isMsie()<=7&&(c.mixin(h.wrapper,{display:"inline",zoom:"1"}),c.mixin(h.query,{marginTop:"-1px"})),c.mixin(b.prototype,d,{_managePreventDefault:function(a){var b,c,d=a.data,e=!1;switch(a.type){case"tabKeyed":b=this.inputView.getHintValue(),c=this.inputView.getInputValue(),e=b&&b!==c;break;case"upKeyed":case"downKeyed":e=!d.shiftKey&&!d.ctrlKey&&!d.metaKey}e&&d.preventDefault()},_setLanguageDirection:function(){var a=this.inputView.getLanguageDirection();a!==this.dir&&(this.dir=a,this.$node.css("direction",a),this.dropdownView.setLanguageDirection(a))},_updateHint:function(){var a,b,d,e,f,g=this.dropdownView.getFirstSuggestion(),h=g?g.value:null,i=this.dropdownView.isVisible(),j=this.inputView.isOverflow();h&&i&&!j&&(a=this.inputView.getInputValue(),b=a.replace(/\s{2,}/g," ").replace(/^\s+/g,""),d=c.escapeRegExChars(b),e=new RegExp("^(?:"+d+")(.*$)","i"),f=e.exec(h),this.inputView.setHintValue(a+(f?f[1]:"")))},_clearHint:function(){this.inputView.setHintValue("")},_clearSuggestions:function(){this.dropdownView.clearSuggestions()},_setInputValueToQuery:function(){this.inputView.setInputValue(this.inputView.getQuery())},_setInputValueToSuggestionUnderCursor:function(a){var b=a.data;this.inputView.setInputValue(b.value,!0)},_openDropdown:function(){this.dropdownView.open()},_closeDropdown:function(a){this.dropdownView["blured"===a.type?"closeUnlessMouseIsOverDropdown":"close"]()},_moveDropdownCursor:function(a){var b=a.data;b.shiftKey||b.ctrlKey||b.metaKey||this.dropdownView["upKeyed"===a.type?"moveCursorUp":"moveCursorDown"]()},_handleSelection:function(a){var b="suggestionSelected"===a.type,d=b?a.data:this.dropdownView.getSuggestionUnderCursor();d&&(this.inputView.setInputValue(d.value),b?this.inputView.focus():a.data.preventDefault(),b&&c.isMsie()?c.defer(this.dropdownView.close):this.dropdownView.close(),this.eventBus.trigger("selected",d.datum,d.dataset))},_getSuggestions:function(){var a=this,b=this.inputView.getQuery();c.isBlankString(b)||c.each(this.datasets,function(c,d){d.getSuggestions(b,function(c){b===a.inputView.getQuery()&&a.dropdownView.renderSuggestions(d,c)})})},_autocomplete:function(a){var b,c,d,e,f;("rightKeyed"!==a.type&&"leftKeyed"!==a.type||(b=this.inputView.isCursorAtEnd(),c="ltr"===this.inputView.getLanguageDirection()?"leftKeyed"===a.type:"rightKeyed"===a.type,b&&!c))&&(d=this.inputView.getQuery(),e=this.inputView.getHintValue(),""!==e&&d!==e&&(f=this.dropdownView.getFirstSuggestion(),this.inputView.setInputValue(f.value),this.eventBus.trigger("autocompleted",f.datum,f.dataset)))},_propagateEvent:function(a){this.eventBus.trigger(a.type)},destroy:function(){this.inputView.destroy(),this.dropdownView.destroy(),f(this.$node),this.$node=null},setQuery:function(a){this.inputView.setQuery(a),this.inputView.setInputValue(a),this._clearHint(),this._clearSuggestions(),this._getSuggestions()}}),b}();!function(){var b,d={},f="ttView";b={initialize:function(b){function g(){var b,d=a(this),g=new e({el:d});b=c.map(h,function(a){return a.initialize()}),d.data(f,new l({input:d,eventBus:g=new e({el:d}),datasets:h})),a.when.apply(a,b).always(function(){c.defer(function(){g.trigger("initialized")})})}var h;return b=c.isArray(b)?b:[b],0===b.length&&a.error("no datasets provided"),h=c.map(b,function(a){var b=d[a.name]?d[a.name]:new i(a);return a.name&&(d[a.name]=b),b}),this.each(g)},destroy:function(){function b(){var b=a(this),c=b.data(f);c&&(c.destroy(),b.removeData(f))}return this.each(b)},setQuery:function(b){function c(){var c=a(this).data(f);c&&c.setQuery(b)}return this.each(c)}},jQuery.fn.typeahead=function(a){return b[a]?b[a].apply(this,[].slice.call(arguments,1)):b.initialize.apply(this,arguments)}}()}(window.jQuery);
\ No newline at end of file