cluster_search_ui/commit

Added old cluster_search config available file.

authorChris Dijkshoorn
Sat Dec 13 13:22:50 2014 +0100
committerChris Dijkshoorn
Sat Dec 13 13:22:50 2014 +0100
commit2308f004c307511b678d5c31a3fb3eabbc29871b
tree6a7c1d205570de0b81f7e2fc15ee4dbc80a32dd1
parentec2012f112c4daa4a1b3ba02ddaae0b4e9dd4e08
Diff style: patch stat
diff --git a/config-available/cluster_search_ui.pl b/config-available/cluster_search_ui.pl
index 908828d..38203e5 100644
--- a/config-available/cluster_search_ui.pl
+++ b/config-available/cluster_search_ui.pl
@@ -1,5 +1,15 @@
-:- module(conf_cluster_search_ui, []).
+:- module(conf_cluster_search, []).
 
-/** <module> Frontend for cluster search
+/** <module> search based on clustering paths in the graph
 */
 
+:- use_module(library('semweb/rdf_db')).
+:- use_module(library('semweb/rdf_library')).
+
+:- rdf_attach_library(cluster_search(rdf)).
+:- rdf_load_library('cluster-search-ui-schema').
+:- rdf_load_library('cluster-search-schema').
+:- rdf_load_library('rijksmuseum-search-ui').
+:- rdf_load_library('bird-search-ui').
+
+:- use_module(api(cluster_search)).
diff --git a/lib/cluster_search_ui/settings.pl b/lib/cluster_search_ui/settings.pl
new file mode 100644
index 0000000..c1c12f5
--- /dev/null
+++ b/lib/cluster_search_ui/settings.pl
@@ -0,0 +1,48 @@
+:- module(cluster_search_settings, []).
+
+:- use_module(library(settings)).
+
+/***************************************************
+* Cluster search settings
+***************************************************/
+
+:- setting(search:basic_search_target, uri, 'http://www.europeana.eu/schemas/edm/ProvidedCHO',
+	   'Default Target for search').
+:- setting(search:threshold, float, 0.05,
+           'Graph-search threshold').
+:- setting(search:literal_threshold, float, 0.05,
+	   'Literal-search threshold').
+:- setting(search:literal_score, boolean, true,
+	   'Use score of string match in threshold of graph search').
+:- setting(search:steps, nonneg, 1000,
+           'Maximum number of steps in the graph search (0 is unbound)').
+:- setting(search:edge_limit, nonneg, 0,
+	   'Limit extension of Node with a maximum number of edges \c
+	   (0 is unbound)').
+:- setting(search:max,   nonneg, 100,
+           'Maximum number of results shown in the output').
+:- setting(search:cluster, oneof([concept, path, spath, role]), spath,
+           'Create clusters by graph path or schema path').
+:- setting(search:search_path, oneof([best, breadth]), best,
+           'Create clusters on best or shortest path').
+:- setting(search:sort, oneof([score, path_length, false]), score,
+           'Sort the results by').
+:- setting(search:prune, boolean, true,
+	   'Prune the search Graph').
+:- setting(search:search_type, oneof([literal,concept,backward]), backward,
+	   'Method to traverse the graph').
+% frontend settings
+:- setting(search:strategy, atom, cluster,
+	   'The strategy used for searching.').
+:- setting(search:image_filter, atom, only_images,
+	   'Filter used for presenting the results.').
+:- setting(search:enrichment, atom, thumbnails,
+	   '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, false,
+	   '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.pl b/lib/cluster_search_ui/web_ui.pl
new file mode 100644
index 0000000..973476c
--- /dev/null
+++ b/lib/cluster_search_ui/web_ui.pl
@@ -0,0 +1,671 @@
+:- module(web_ui, [
+	    web/1,
+	    results/1,
+	    about/1,
+	    result/1,
+	    analytics/1
+	  ]).
+/** <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(http/html_write)).
+:- use_module(library(http/html_head)).
+:- use_module(library(http/http_path)).
+:- use_module(library(http/http_parameters)).
+:- 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(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)).
+
+:- 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).
+
+%%	web(+Request) is det.
+%
+%	If query is given, generate results page, fron page otherwise.
+web(_Request) :-
+    reply_page(front, _Options).
+
+%%	results(+Request) is det.
+%
+%	Generate results page.
+results(Request) :-
+    get_parameters(Request, Options),
+    reply_page(results, Options).
+
+%%	restult(+Request) is det.
+%
+%	Generate a page showing a result with its metadata.
+result(Request) :-
+    get_parameters(Request, Options),
+    reply_page(result, Options).
+
+%%	about(+Request) is det.
+%
+%	Generate about page.
+about(Request) :-
+    get_parameters(Request, Options),
+    reply_page(about, Options).
+
+%%	analytics(+Request) is det.
+%
+%	Generate analytics page.
+analytics(Request) :-
+    get_parameters(Request, Options),
+    reply_page(analytics, Options).
+
+
+%%	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(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)
+    ]).
+
+%%	content(+Type, +Options)
+%
+%	Returns the content according to the type of page. Four
+%	different types are possible: front, results, result and about.
+content(front, _) -->
+    {get_carousel_items(CarouselItems)},
+    carousel(CarouselItems).
+
+content(results, Options) -->
+    results_page(cluster, Options).
+
+content(result, Options) -->
+    {option(uri(Uri), Options),
+     setting(search:annotate, Annotate),
+     (Annotate
+     ->	 get_annotation_options(Uri, AnnotationOrImage)
+     ;	 get_image_options(Uri, AnnotationOrImage)
+     ),
+     findall([Predicate, Object], rdf(Uri, Predicate, Object), Metadata)
+    },
+    html([\result_page_body(Annotate, AnnotationOrImage),
+	  div([class('row'), id('metadata')],div([class('well well-sm')],dl(class('dl-horizontal'),
+	  \metadata(Metadata))))
+	 ]).
+
+content(about, _) -->
+    {current_prolog_flag(version, Version),
+     setting(search:ui, UI),
+     rdf(UI, dcterms:title, literal(lang(en, Title)))
+    },
+    html({|html(Title, Version)||
+	  <div class="row">
+	  <div class="col-md-10 col-md-offset-1">
+	  <h3>About <span>Title</span></h3>
+
+	  <p>This website is used to demo semantic search strategies, developed at the <a href="http://wm.cs.vu.nl/">Web and Media group </a>of the VU University Amsterdam. The images originate from the <a href="https://www.rijksmuseum.nl/">Rijksmuseum Amsterdam</a>. This work is done in the context of the <a href="http://sealincmedia.wordpress.com/">SEALINCMedia</a> project. For more information contact <a href="http://www.few.vu.nl/~cdn370/">Chris Dijkshoorn</a>.
+	  </p>
+
+	  <p><span>Title</span> is running on <a href="http://cliopatria.swi-prolog.org/">Cliopatria</a> powered by <a href="http://www.swi-prolog.org/">Prolog</a> version <span>Version</span>. The code is available on <a href="https://github.com/rasvaan/cluster_search/">Github</a>, you are welcome to report bugs or file feature requests.
+	  </p>
+	  </div>
+	  </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).
+
+get_annotation_options(Uri, AnnotationOptions) :-
+    AnnotationUI = 'http://semanticweb.cs.vu.nl/annotate/nicheAccuratorBirdDemoUi',
+    AnnotationFields = [
+	 'http://semanticweb.cs.vu.nl/annotate/example#IOCCommonNameAnnotation',
+	 'http://semanticweb.cs.vu.nl/annotate/example#IOCScientificNameAnnotation'],
+     get_metafields(AnnotationUI, [], MetadataFields),
+     query_title(Uri, Title),
+     AnnotationOptions = [
+	 target(Uri),
+	 ui(AnnotationUI),
+	 title(Title),
+	 user('http://invenit.user.nl/'),
+	 annotation_fields(AnnotationFields),
+	 metadata_fields(MetadataFields)
+     ].
+
+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)
+%
+%	Retrieve items for the carousel from the RDF store.
+get_carousel_items(CarouselItems) :-
+    findall(item(LocationAbsolute, Action, Title),
+	    (	rdf(Item, rdf:type, ui:carouselItem),
+		rdf(Item, ui:imageLocation, literal(LocationRelative)),
+		http_absolute_location(img(LocationRelative), LocationAbsolute, []),
+		rdf(Item, ui:action, literal(Action)),
+		rdf(Item, dcterms:title, literal(lang(en, Title)))
+	    ),
+	    CarouselItems).
+
+:- multifile cliopatria:image_url/2.
+%%	image_url(+Uri, -ImageUrl) is det.
+%
+%	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 is present in database, remove
+%	isShownBy triple. If not present in cache, database and at RMA,
+%	send image stub.
+image_url(Uri, ImageUrl) :-
+    cliopatria:image_url(Uri, ImageUrl).
+
+image_url(Uri, ImageUrl) :-
+    rdf(Aggregation, edm:aggregatedCHO, Uri),
+    rdf(Aggregation, edm:isShownBy, Image),
+    url_cached(Image, file(_)),
+    !,
+    concat('cache/original?uri=', Image, RequestUrl),
+    http_absolute_location(root(RequestUrl), ImageUrl, []).
+
+image_url(Uri, ImageUrl) :-
+    rdf(Aggregation, edm:aggregatedCHO, Uri),
+    rdf(Aggregation, edm:isShownBy, Image),
+    https_header_response(Image, Status),
+    Status == 200,
+    !,
+    concat('cache/original?uri=', Image, RequestUrl),
+    http_absolute_location(root(RequestUrl), ImageUrl, []).
+
+image_url(Uri, Stub) :-
+    rdf(Aggregation, edm:aggregatedCHO, Uri),
+    rdf(Aggregation, edm:isShownBy, Image),
+    !,
+    rdf_retractall(Uri, edm:isShownBy, Image),
+    http_absolute_location(icons('stub.png'), Stub, []).
+
+image_url(_, Stub) :- http_absolute_location(icons('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.
+%%	ssl_verify(+SSL, +ProblemCert, +AllCerts, +FirstCert, +Error)
+%
+%	Currently we accept  all  certificates.
+ssl_verify(_SSL, _ProblemCertificate, _AllCertificates, _FirstCertificate, _Error).
+
+/***************************************************
+* web page elements dcg
+***************************************************/
+
+%%	title(+Page)
+%
+%	Replies the title for the given page.
+title(front, _) -->
+    {setting(search:ui, UI),
+    rdf(UI, dcterms:title, literal(lang(en, Title)))},
+    html(title(Title)).
+title(about, _) -->
+    {setting(search:ui, UI),
+    rdf(UI, dcterms:title, literal(lang(en, Title))),
+    concat('About ', Title, TitleAbout)
+    },
+    html(title(TitleAbout)).
+title(results, _) --> html(title('Results')).
+title(result, Options) -->
+    {option(uri(Uri), Options),
+     query_title(Uri, Title)
+    },
+    html(title(Title)).
+
+title(analytics, _) -->
+    {setting(search:ui, UI),
+    rdf(UI, dcterms:title, literal(lang(en, Title))),
+    concat(Title, ' Statistics', TitleStatistics)},
+    html(title(TitleStatistics)).
+
+result_page_body(true, AnnotationOptions) -->
+    annotation_page_body(AnnotationOptions).
+result_page_body(false, ImageUrl) -->
+    html(img([src(ImageUrl), class('img-responsive'), alt('Image')])).
+
+%%	query_title(+Uri, -Title)
+%
+%	Retrieve the tile of a uri, ignoring the language tag.
+query_title(Uri, Title) :-
+    rdf(Uri, dc:title, literal(lang(_,Title))), !.
+query_title(Uri, Title) :-
+    rdf(Uri, dc:title, literal(Title)).
+
+%%	scripts(+Page)
+%
+%	Replies the scripts needed for the indicated page.
+scripts(front) -->
+    html([\load_javascript(jquery),
+	  \load_javascript(bootstrap),
+	  \load_javascript(type_ahead),
+	  \load_javascript(search),
+	  \load_javascript(google_analytics)]).
+
+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)]).
+
+scripts(result) -->
+    html([\load_javascript(jquery),
+	  \load_javascript(bootstrap),
+	  \load_javascript(type_ahead),
+	  \load_javascript(search),
+	  \load_javascript(google_analytics)]).
+
+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(+Script)
+%
+%	Generates the html to load the indicated script.
+load_javascript(jquery) -->
+    html(script(src('http://code.jquery.com/jquery.js'),'')).
+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),'')).
+load_javascript(pagination) -->
+    {http_absolute_location(js('pagination.js'), JavaScriptPagination, [])},
+    html(script(src(JavaScriptPagination),'')).
+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(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><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(about) -->
+    {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><a href="HttpAnalytics">Statistics</a></li>
+	        <li class="active"><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(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
+metadata([]) --> [].
+metadata([[Predicate,Object]|T]) -->
+    html(\format_metadata(Predicate, Object)),
+    metadata(T).
+
+%%	format_metadata(+Predicate, +Object)
+%
+%	Formats the metadata field into table rows.
+format_metadata(Predicate, Object) -->
+    html(
+	[dt(\rdf_link(Predicate, [resource_format(nslabel)])),
+	 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.
+results_page(cluster, Options) -->
+    {option(query(Query), Options),
+     concat('search(\'', Query, FunctionCall0),
+     concat(FunctionCall0, '\');', FunctionCall),
+     debug(functioncall, 'FunctionCall: ~p', [FunctionCall])
+    },
+    html([div(id('results'),''),script(FunctionCall)]).
+
+%%	carousel(+Items)
+%
+%	Generates a carousel of the image urls and descriptions in
+%	Items.
+carousel(Items) -->
+    html(div([class('carousel slide'),id('exampleCarousel'),'data-interval'('false')],
+	     [\carousel_indicators(Items),
+	      \carousel_items(Items),
+	      \carousel_navigation
+	     ])).
+
+carousel_indicators([First|Items]) -->
+    html(ol(class('carousel-indicators'),
+	    [\first_carousel_indicator(First),
+	     \more_carousel_indicators(Items,0)]
+	   )
+	).
+
+first_carousel_indicator(_) -->
+    html(
+	li(['data-target'('#exampleCarousel'), 'data-slide-to'('0'), class('active')],'')
+    ).
+
+more_carousel_indicators([],_) --> [].
+more_carousel_indicators([_Indicator|Indicators],N) -->
+    {NextN is N+1},
+    indicator(NextN),
+    more_carousel_indicators(Indicators, NextN).
+
+indicator(N) -->
+    html(li(['data-target'('#exampleCarousel'),'data-slide-to'(N)],''
+	   )
+	).
+
+carousel_items([First|Items]) -->
+    html(div(class('carousel-inner'),
+	     [\first_carousel_item(First),
+	      \more_carousel_items(Items)]
+	    )
+	).
+
+first_carousel_item(item(Image, Link, Text)) -->
+    html(
+	div(class('active item'),
+	    [a(href(Link),img([src(Image),alt('Example'),id('example_image')])),
+	     a(href(Link),div(class('carousel-caption'),h2(Text)))
+	    ]
+	   )
+    ).
+
+more_carousel_items([]) --> [].
+more_carousel_items([Item|Items]) -->
+    carousel_item(Item),
+    more_carousel_items(Items).
+
+carousel_item(item(Image, Link, Text)) -->
+    html(
+	div(class('item'),
+	    [a(href(Link),img([src(Image),alt('Example'),id('example_image')])),
+	     a(href(Link),div(class('carousel-caption'),h2(Text)))
+	    ]
+	   )
+    ).
+
+carousel_navigation -->
+    html(
+	[a([class('left carousel-control'), href('#exampleCarousel'), 'data-slide'('prev')],
+	   span(class('icon-prev'),'')),
+	 a([class('right carousel-control'), href('#exampleCarousel'), 'data-slide'('next')],
+	   span(class('icon-next'),''))
+	]
+    ).