amalgame/commit

splitup overly complicated and large applications/startpage.pl into several pieces

authorJacco van Ossenbruggen
Mon Aug 11 15:25:27 2014 +0200
committerJacco van Ossenbruggen
Mon Aug 11 15:25:27 2014 +0200
commit60cdb25e523ef55ed4ad90c2ccf6bb9d5f5c5c17
treea2b50e536882e205cdb719beb3210ef15d067286
parentb13432e048d6afc312907f426751b07861e9c715
Diff style: patch stat
diff --git a/api/form/amalgame/startpage.pl b/api/form/amalgame/startpage.pl
new file mode 100644
index 0000000..eca168c
--- /dev/null
+++ b/api/form/amalgame/startpage.pl
@@ -0,0 +1,221 @@
+:- module(ag_form_startpage,
+	  [
+	  ]).
+
+:- use_module(library(http/http_dispatch)).
+:- use_module(library(http/http_parameters)).
+
+:- use_module(library(semweb/rdf_file_type)).
+:- use_module(user(user_db)).
+
+:- use_module(library(amalgame/rdf_util)).
+:- use_module(library(amalgame/ag_provenance)).
+:- use_module(library(amalgame/util)).
+
+% handlers for the different forms on the start page.
+% most handle the form request and then redirect to some other page,
+% such as the strategy builder or back to the start page:
+
+:- http_handler(amalgame(form/new),       http_ag_form_new_strategy, []).
+:- http_handler(amalgame(form/select),    http_ag_form_select_strategy, []).
+:- http_handler(amalgame(form/url),	  http_ag_form_upload_strategy_resource, []).
+:- http_handler(amalgame(form/data),      http_ag_form_upload_strategy_data, []).
+:- http_handler(amalgame(form/reference), http_ag_form_upload_reference, []).
+
+%%     http_ag_form_select_strategy(+Request)
+%
+%      Execute action on selected strategy and redirect to
+%      appropriate page.
+
+http_ag_form_select_strategy(Request) :-
+	http_parameters(Request,
+			[
+			 strategy(Strategies,
+				    [list(uri),
+				     description('URI of the selected strategy')]),
+			 submit(Action,
+				[oneof(['View selected',
+					'Merge selected',
+					'Delete selected']),
+				 description('Action to be performed on this strategy'),
+				 default('View selected')
+				])
+		       ]),
+	(   Action == 'View selected'
+	->  build_redirect(Request, Strategies)
+	;   Action == 'Merge selected'
+	->  merge_redirect(Request, Strategies)
+	;   Action == 'Delete selected'
+	->  delete_redirect(Request, Strategies)
+	).
+
+%%	http_ag_form_new_strategy(+Request)
+%
+%	Handle form data to create a new strategy
+
+http_ag_form_new_strategy(Request) :-
+	http_parameters(Request,
+			[ scheme(Schemes,
+				 [zero_or_more,
+				  description('Zero or more concept schemes')])
+			]),
+	new_strategy(Graph, [schemes(Schemes), comment('New strategy')]),
+	build_redirect(Request, [Graph]).
+
+
+
+%%      http_ag_form_upload_strategy_data(+Request) is det.
+%
+%	Handler for strategy form data import.
+
+http_ag_form_upload_strategy_data(Request) :-
+	authorized(write(default, _)),
+	http_parameters(Request,
+			[ data(Data,
+			       [ description('RDF data to be loaded')
+			       ])
+			]),
+	rdf_bnode(TmpGraph),
+	atom_to_memory_file(Data, MemFile),
+	setup_call_cleanup(open_memory_file(MemFile, read, Stream),
+			   rdf_guess_format_and_load(Stream, [graph(TmpGraph)]),
+			   ( close(Stream),
+			     free_memory_file(MemFile)
+			   )),
+	cp_strategy_from_tmp(Request, TmpGraph).
+
+%%      http_ag_form_upload_strategy_resource(+Request) is det.
+%
+%	Handler for strategy form resource import.
+
+http_ag_form_upload_strategy_resource(Request) :-
+	authorized(write(default, _)),
+	http_parameters(Request,
+			[ url(URL, [])
+			]),
+	rdf_bnode(TmpGraph),
+	rdf_load(URL, [graph(TmpGraph)]),
+	cp_strategy_from_tmp(Request, TmpGraph).
+
+%%	http_ag_form_upload_reference(+Request) is det.
+%
+%	Handle form to upload an existing strategy
+http_ag_form_upload_reference(Request) :-
+	authorized(write(default, _)),
+	http_parameters(Request,
+			[ data(Data,
+			       [ description('RDF data to be loaded')
+			       ])
+			]),
+	new_reference_name(NamedGraph),
+	atom_to_memory_file(Data, MemFile),
+	setup_call_cleanup(open_memory_file(MemFile, read, Stream),
+			   rdf_guess_format_and_load(Stream, [graph(NamedGraph)]),
+			   ( close(Stream),
+			     free_memory_file(MemFile)
+			   )),
+	rdf_equal(amalgame:'LoadedMapping', LMGraph),
+	rdf_assert(NamedGraph, rdf:type, amalgame:'LoadedMapping', LMGraph),
+
+	http_link_to_id(list_graph, [graph(NamedGraph)], ListGraph),
+	http_redirect(moved, ListGraph, Request).
+
+
+
+cp_strategy_from_tmp(Request, TmpGraph) :-
+	rdf(Strategy, rdf:type, amalgame:'AlignmentStrategy', TmpGraph),!,
+	cp_graph(TmpGraph, Strategy, true),
+	rdf_unload_graph(TmpGraph),
+	build_redirect(Request, [Strategy]).
+
+build_redirect(Request, [Strategy|_]) :-
+	http_link_to_id(http_ag_build, [strategy(Strategy)], Redirect),
+	http_redirect(moved, Redirect, Request).
+
+delete_redirect(Request, Strategies) :-
+	authorized(write(default, _)),
+	forall(member(Strategy, Strategies),
+	       (   (   provenance_graph(Strategy, Prov)
+		   ->  rdf_unload_graph(Prov)
+		   ;   true
+		   ),
+		   rdf_unload_graph(Strategy)
+	       )
+	      ),
+	http_link_to_id(http_amalgame_main_page, [], Redirect),
+	http_redirect(moved, Redirect, Request).
+
+merge_redirect(Request, Strategies) :-
+	% Create comment
+	maplist(scheme_label, Strategies, Labeled),
+	keysort(Labeled, Sorted),
+	pairs_keys(Sorted, Labels),
+	atomic_list_concat(Labels, ', ', LabelsAtom),
+	atomic_concat('Strategy merged from ', LabelsAtom, Comment),
+
+	% Create merged strategy
+	new_strategy(New, [comment(Comment)]),
+	cp_graphs(Strategies, New),
+	merge_strategy_nodes(Strategies, New),
+
+	% Redirect to builder
+	http_link_to_id(http_ag_build, [strategy(New)], Redirect),
+	http_redirect(moved, Redirect, Request).
+
+new_reference_name(Reference) :-
+	setting(amalgame:default_publish_namespace, NS),
+	reset_gensym(reference_alignment),
+	repeat,
+	gensym(reference_alignment, Local),
+	atomic_list_concat([NS,Local], Reference),
+	\+ rdf_graph(Reference),
+	!.
+
+
+merge_strategy_nodes([], _New) :- !.
+merge_strategy_nodes([H|T], New) :-
+	findall(rdf(H,P,O),
+		rdf(H,P,O,New),
+		Triples),
+	forall(member(rdf(_,P,O), Triples),
+	       rdf_assert(New,P,O,New)),
+	merge_strategy_nodes(T, New).
+
+%%	new_strategy(-StrategyURI, Options)
+%
+%	Assert a new strategy graph.
+
+new_strategy(S, Options) :-
+	authorized(write(default, _)),
+	new_strategy_name(S, NS),
+	rdf_assert(S, rdf:type, amalgame:'AlignmentStrategy', S),
+	rdf_assert(S, rdf:type, prov:'Plan', S),
+	rdf_assert(S, amalgame:publish_ns, NS, S),
+	assert_user_provenance(S, S),
+
+	(   option(schemes(Schemes), Options)
+	->  add_schemes(Schemes, S)
+	;   true),
+
+	(   option(comment(C), Options)
+	->  rdf_assert(S, rdfs:comment, literal(C), S)
+	;   true
+	).
+
+scheme_label(URI, Key-URI) :-
+	rdf_graph_label(URI, CasedKey),
+	downcase_atom(CasedKey, Key).
+
+add_schemes([], _).
+add_schemes([Scheme|Ss], Strategy) :-
+	rdf_assert(Strategy, amalgame:includes, Scheme, Strategy),
+	add_schemes(Ss, Strategy).
+
+new_strategy_name(Strategy, NS) :-
+	setting(amalgame:default_publish_namespace, NS),
+	reset_gensym(strategy),
+	repeat,
+	gensym(strategy, Local),
+	atomic_list_concat([NS,Local], Strategy),
+	\+ rdf_graph(Strategy),
+	!.
diff --git a/applications/startpage.pl b/applications/startpage.pl
index b16854a..67a348d 100644
--- a/applications/startpage.pl
+++ b/applications/startpage.pl
@@ -2,26 +2,18 @@
 	  [html_schemes_only//0  % for backward compat with europeana demo
 	  ]).
 
-:- use_module(library(option)).
+
 :- use_module(library(http/http_dispatch)).
-:- use_module(library(http/http_parameters)).
 :- use_module(library(http/http_path)).
 :- use_module(library(http/html_head)).
 :- use_module(library(http/html_write)).
-:- use_module(library(semweb/rdf_db)).
-:- use_module(library(semweb/rdf_label)).
-:- use_module(library(semweb/rdf_file_type)).
-
-:- use_module(user(user_db)).
 
 :- use_module(library(yui3_beta)).
-:- use_module(components(label)).
 :- use_module(library(amalgame/util)).
-:- use_module(library(amalgame/voc_stats)).
-:- use_module(library(amalgame/ag_provenance)).
 :- use_module(applications(skos_browser)).
 
-:- use_module(components(amalgame/util)).
+:- use_module(components(amalgame/startpage)).
+:- use_module(api(form/amalgame/startpage)).
 
 % main http handler for amalgame:
 :- http_handler(amalgame(.), http_amalgame_main_page, []).
@@ -30,14 +22,6 @@
 :- http_handler(amalgame(eq),	    http_redirect(moved, amalgame(.)), []).
 :- http_handler(amalgame(app/main), http_redirect(moved, amalgame(.)), []).
 
-% handlers for the different forms on the main page.
-% most handle the form request and then redirect to some other page,
-% such as the strategy builder or the main page:
-:- http_handler(amalgame(form/new),       http_ag_form_new_strategy, []).
-:- http_handler(amalgame(form/select),    http_ag_form_select_strategy, []).
-:- http_handler(amalgame(form/url),	  http_ag_form_upload_strategy_resource, []).
-:- http_handler(amalgame(form/data),      http_ag_form_upload_strategy_data, []).
-:- http_handler(amalgame(form/reference), http_ag_form_upload_reference, []).
 
 %%      http_amalgame_main_page(+Request) is det.
 %
@@ -47,123 +31,15 @@
 http_amalgame_main_page(Request) :-
 	html_main_page(Request).
 
-
-%%     http_ag_form_select_strategy(+Request)
-%
-%      Execute action on selected strategy and redirect to
-%      appropriate page.
-
-http_ag_form_select_strategy(Request) :-
-	http_parameters(Request,
-			[
-			 strategy(Strategies,
-				    [list(uri),
-				     description('URI of the selected strategy')]),
-			 submit(Action,
-				[oneof(['View selected',
-					'Merge selected',
-					'Delete selected']),
-				 description('Action to be performed on this strategy'),
-				 default('View selected')
-				])
-		       ]),
-	(   Action == 'View selected'
-	->  build_redirect(Request, Strategies)
-	;   Action == 'Merge selected'
-	->  merge_redirect(Request, Strategies)
-	;   Action == 'Delete selected'
-	->  delete_redirect(Request, Strategies)
-	).
-
-%%	http_ag_form_new_strategy(+Request)
-%
-%	Handle form data to create a new strategy
-
-http_ag_form_new_strategy(Request) :-
-	http_parameters(Request,
-			[ scheme(Schemes,
-				 [zero_or_more,
-				  description('Zero or more concept schemes')])
-			]),
-	new_strategy(Graph, [schemes(Schemes), comment('New strategy')]),
-	build_redirect(Request, [Graph]).
-
-
-
-%%      http_ag_form_upload_strategy_data(+Request) is det.
-%
-%	Handler for strategy form data import.
-
-http_ag_form_upload_strategy_data(Request) :-
-	authorized(write(default, _)),
-	http_parameters(Request,
-			[ data(Data,
-			       [ description('RDF data to be loaded')
-			       ])
-			]),
-	rdf_bnode(TmpGraph),
-	atom_to_memory_file(Data, MemFile),
-	setup_call_cleanup(open_memory_file(MemFile, read, Stream),
-			   rdf_guess_format_and_load(Stream, [graph(TmpGraph)]),
-			   ( close(Stream),
-			     free_memory_file(MemFile)
-			   )),
-	cp_strategy_from_tmp(Request, TmpGraph).
-
-%%      http_ag_form_upload_strategy_resource(+Request) is det.
-%
-%	Handler for strategy form resource import.
-
-http_ag_form_upload_strategy_resource(Request) :-
-	authorized(write(default, _)),
-	http_parameters(Request,
-			[ url(URL, [])
-			]),
-	rdf_bnode(TmpGraph),
-	rdf_load(URL, [graph(TmpGraph)]),
-	cp_strategy_from_tmp(Request, TmpGraph).
-
-%%	http_ag_form_upload_reference(+Request) is det.
-%
-%	Handle form to upload an existing strategy
-http_ag_form_upload_reference(Request) :-
-	authorized(write(default, _)),
-	http_parameters(Request,
-			[ data(Data,
-			       [ description('RDF data to be loaded')
-			       ])
-			]),
-	new_reference_name(NamedGraph),
-	atom_to_memory_file(Data, MemFile),
-	setup_call_cleanup(open_memory_file(MemFile, read, Stream),
-			   rdf_guess_format_and_load(Stream, [graph(NamedGraph)]),
-			   ( close(Stream),
-			     free_memory_file(MemFile)
-			   )),
-	rdf_equal(amalgame:'LoadedMapping', LMGraph),
-	rdf_assert(NamedGraph, rdf:type, amalgame:'LoadedMapping', LMGraph),
-
-	http_link_to_id(list_graph, [graph(NamedGraph)], ListGraph),
-	http_redirect(moved, ListGraph, Request).
-
-
-find_schemes(Schemes) :-
-	findall(C,
-		(   is_vocabulary(C),
-		    voc_property(C, virtual(false))
-		),
-		All),
-	maplist(scheme_label, All, Labeled),
-	keysort(Labeled, Sorted),
-	pairs_values(Sorted, Schemes).
-
-scheme_label(URI, Key-URI) :-
-	graph_label(URI, CasedKey),
-	downcase_atom(CasedKey, Key).
+html_schemes_only -->
+	{
+	 amalgame_alignable_schemes(ConceptSchemes)
+	},
+	html_new(ConceptSchemes).
 
 html_main_page(_Request) :-
 	findall(A-S, amalgame_strategy_schemes(A, S), Alignments),
-	find_schemes(ConceptSchemes),
+	amalgame_alignable_schemes(ConceptSchemes),
 	reply_html_page(cliopatria(main),
 			[ title(['Amalgame - strategies'])
 			],
@@ -193,313 +69,6 @@ html_main_page(_Request) :-
 			]).
 
 
-html_schemes_only -->
-	{
-	 find_schemes(ConceptSchemes)
-	},
-	html_new(ConceptSchemes).
-
-%%	html_new
-%
-%
-
-html_new([]) -->
-	html_acc_item(new,
-		      'new alignment strategy: no (SKOS) vocabularies found',
-		      div([style('padding: 1%')],[
-			  'Please use the Repository drop-down menu to load ',
-			  'the vocabularies you would like to align ',
-			  'into the repository/triple store.'
-		      ]),
-		      [active]
-		     ).
-
-html_new(Schemes) -->
-	{ has_write_permission, !,
-	  ButtonsBottom = div(\html_submit('Start')),
-	  length(Schemes, N),
-	  (   N > 7
-	  ->  ButtonsTop = ButtonsBottom
-	  ;   ButtonsTop = div([],[])
-	  )
-	},
-	html_acc_item(new,
-		      'new alignment strategy',
-		      [ form(action(location_by_id(http_ag_form_new_strategy)),
-			     [  ButtonsTop,
-				\html_vocab_table(Schemes),
-				ButtonsBottom
-			     ])
-		      ],
-		      [active]
-		     ).
-
-html_new(_) -->
-	{
-	 http_location_by_id(http_amalgame_main_page, This),
-	 http_link_to_id(cliopatria_openid:login_page,
-			 ['openid.return_to'(This)], Login)
-	},
-	html_acc_item(new,
-		      'please login to access other functions',
-		      [
-			  div(a([class(login), href(Login)], ['login']))
-		      ],
-		      [inactive]
-		     ).
-
-html_vocab_table(Vs) -->
-	html([
-	    \html_requires(sortable),
-	    table([class(sortable)],
-		   [thead(tr(\html_vocab_head)),
-		    tbody(\html_vocab_rows(Vs))
-		   ])
-	]).
-
-html_vocab_head -->
-	html([th([]),
-	      th(class(name),       name),
-	      th(class(version),    version),
-	      th(class(count),     'estimated #concepts'),
-	      th(class(preflangs), 'prefLabels'),
-	      th(class(altlangs),  'altLabels')
-	     ]).
-
-html_vocab_rows([]) --> !.
-html_vocab_rows([Scheme|Vs]) --> {
-    (   voc_property(Scheme, numberOfConcepts(ConceptCount), [compute(false)])
-    ->  true
-    ;   rdf_estimate_complexity(_, skos:inScheme, Scheme, ConceptCount)
-    ),
-    voc_property(Scheme, languages(skos:prefLabel, PrefLangs)),
-    voc_property(Scheme, languages(skos:altLabel, AltLangs)),
-    voc_property(Scheme, version(Version0)),
-    (	Version0 == ''
-    ->	voc_property(Scheme, revision(Version))
-    ;	Version = Version0
-    )
-},
-	html(tr([td(input([type(checkbox), autocomplete(off), class(option),
-			   name(scheme), value(Scheme)])),
-		 td(class(name),    \html_scheme_name(Scheme)),
-		 td(class(version), Version),
-		 td(class(count), ConceptCount),
-		 td([span(class(preflangs), \html_showlist(PrefLangs))]),
-		 td([span(class(altlangs),  \html_showlist(AltLangs) )])
-
-		])),
-	html_vocab_rows(Vs).
-
-
-%%	html_open(+Alignments)
-%
-%
-html_open([]) -->
-	html_acc_item(open,
-		      div([style('font-style: italic; color: gray')],
-			  'no strategies have been created yet'),
-		      [],
-		      [inactive]),
-	!.
-html_open(Alignments) -->
-	{ ButtonsBottom = div([ \html_submit('View selected'),
-			  \html_submit('Merge selected'),
-			  \html_submit('Delete selected')
-			]),
-	  length(Alignments, N),
-	  (   N > 7
-	  ->  ButtonsTop = ButtonsBottom
-	  ;   ButtonsTop = div([],[])
-	  )
-	},
-	html_acc_item(open,
-		      'edit/delete pre-loaded alignment strategy',
-		      [ form(action(location_by_id(http_ag_form_select_strategy)),
-			     [
-				 ButtonsTop,
-				 \html_strategy_table(Alignments,
-						       [linkto(http_ag_build)]),
-				 ButtonsBottom
-
-			     ])
-		      ],
-		      [active]
-		     ).
-html_publish([]) -->
-	html_acc_item(open,
-		      div([style('font-style: italic; color: gray')],
-			  'no mappings have been created yet'),
-		      [],
-		      [inactive]),
-	!.
-html_publish(Strategies) -->
-	{
-	 has_write_permission,
-	 L=http_ag_publish_form,
-	 !
-	},
-	html_acc_item(publish,
-		      'publish alignment strategy results',
-		      [ form(action(location_by_id(L)),
-			     [ \html_strategy_table(Strategies, [linkto(L)]),
-			       \html_submit('Publish')
-			     ])
-		      ],
-		      [inactive]).
-html_publish(_) -->  !.
-
-
-%%	html_strategy_table(+Graphs, +Options)
-%
-%	Emit HTML table with strategy graph properties.
-
-html_strategy_table(Strategies, Options) -->
-	html([
-	    \html_requires(sortable),
-	    table(
-		[class(sortable)],
-		[ thead(tr(\html_alignment_head)),
-		  tbody(\html_alignment_rows(Strategies, Options))
-		])
-	]).
-
-html_alignment_head -->
-	html([th([]),
-	      th(name),
-	      th(includes),
-	      th('Created by:'),
-	      th('Comment:')
-	     ]).
-
-html_alignment_rows([],_) --> !.
-html_alignment_rows([URI-Schemes|Gs], Options) -->
-	{
-	 (   rdf(URI, dcterms:creator, Author, URI)
-	 ->  true
-	 ;   Author = anonymous
-	 ),
-	 (   rdf(URI, rdfs:comment, CommentR, URI)
-	 ->  literal_text(CommentR, Comment)
-	 ;   Comment = ''
-	 )
-	},
-	html(tr([td(input([type(checkbox), autocomplete(off), class(option), name(strategy), value(URI)])),
-		 td(\html_strategy_name(URI, Options)),
-		 td(\html_scheme_labels(Schemes)),
-		 td(\turtle_label(Author)),
-		 td([class(comment)],Comment)
-		])),
-	html_alignment_rows(Gs, Options).
-
-html_scheme_labels([]) --> !.
-html_scheme_labels([S|Ss]) -->
-	html(div(\turtle_label(S))),
-	html_scheme_labels(Ss).
-
-html_strategy_name(Graph, Options) -->
-	{ graph_label(Graph, Label),
-	  option(linkto(LinkTo), Options, http_ag_build),
-	  http_link_to_id(LinkTo, [strategy(Graph)], Link)
-	},
-	html(a([href(Link)],Label)).
-
-html_scheme_name(Graph) -->
-	{ graph_label(Graph, Label),
-	  http_link_to_id(http_skos_browser, [scheme(Graph)], Link)
-	},
-	html(a([href(Link)],Label)).
-
-graph_label(Graph, Label) :-
-	rdf_display_label(Graph, Lit),
-	literal_text(Lit, Label),!.
-graph_label(Graph, Graph).
-
-html_reference -->
-	{ has_write_permission,
-	  !
-	},
-	html_acc_item(reference,
-		      'upload existing/reference alignment',
-		      form([action(location_by_id(http_ag_form_upload_reference)),
-			    method('POST'),
-			    enctype('multipart/form-data') ],
-			   [ p(['Upload an exisiting alignment to build upon, ',
-				'or to use as reference (ground truth)' ]),
-			     input([type(file), name(data),
-				    size(50), autocomplete(off)
-				   ]),
-			     input([type(submit), value('Upload')])
-			   ]),
-		      [inactive]
-		     ).
-
-html_reference --> !.
-
-html_import -->
-	{
-	 has_write_permission,
-	 !
-	},
-	html_acc_item(import,
-		      'upload strategy or clone execution trace',
-		      [ form([action(location_by_id(http_ag_form_upload_strategy_resource)),
-			      method('POST')
-			     ],
-			     [ 'URL: ',
-			       input([type(text), name(url), value('http://'),
-				      autocomplete(off), size(50)
-				     ]),
-			       input([type(submit), value('Upload')])
-			   ]),
-			form([action(location_by_id(http_ag_form_upload_strategy_data)),
-			      method('POST'),
-			      enctype('multipart/form-data')
-			     ],
-			     [ 'File: ',
-			       input([type(file), name(data),
-				      size(50)%, autocomplete(off)
-				     ]),
-			       input([type(submit), value('Upload')])
-			     ])
-		      ],
-		      [inactive]).
-
-html_import --> !.
-
-%%	html_submit(+Label)
-%
-%
-
-html_submit(Label) -->
-	html(span(class(controls),
-		 [ input([type(submit), autocomplete(off), class(start),
-			  name(submit), disabled(true), value(Label)])
-		 ])).
-
-
-%%	html_acc_item(+Id, +Label, +HTMLBody, +Options)
-%
-%	Emit html markup for a YUI3 accordion item.
-%	Options:
-%
-%	* active/inactive
-
-html_acc_item(Id, Label, Body, Options) -->
-	{ (   option(active, Options)
-	  ->  Class = 'yui3-accordion-item yui3-accordion-item-active'
-	  ;   Class = 'yui3-accordion-item'
-	  )
-	},
-	html(div([class(Class), id(Id)],
-		 [ div(class('yui3-accordion-item-hd'),
-		       a([href('javascript:{}'), class('yui3-accordion-item-trigger')],
-			   Label)),
-		   div(class('yui3-accordion-item-bd'),
-		       Body)
-		 ])).
-
-
 %%	yui_script
 %
 %	Emit YUI object.
@@ -528,108 +97,9 @@ js_module(startpage, json([fullpath(Path),
 	http_absolute_location(js('startpage.js'), Path, []).
 
 
-%%	new_strategy(-StrategyURI, Options)
-%
-%	Assert a new strategy graph.
-
-new_strategy(S, Options) :-
-	authorized(write(default, _)),
-	new_strategy_name(S, NS),
-	rdf_assert(S, rdf:type, amalgame:'AlignmentStrategy', S),
-	rdf_assert(S, rdf:type, prov:'Plan', S),
-	rdf_assert(S, amalgame:publish_ns, NS, S),
-	assert_user_provenance(S, S),
-
-	(   option(schemes(Schemes), Options)
-	->  add_schemes(Schemes, S)
-	;   true),
-
-	(   option(comment(C), Options)
-	->  rdf_assert(S, rdfs:comment, literal(C), S)
-	;   true
-	).
-
-add_schemes([], _).
-add_schemes([Scheme|Ss], Strategy) :-
-	rdf_assert(Strategy, amalgame:includes, Scheme, Strategy),
-	add_schemes(Ss, Strategy).
-
-new_strategy_name(Strategy, NS) :-
-	setting(amalgame:default_publish_namespace, NS),
-	reset_gensym(strategy),
-	repeat,
-	gensym(strategy, Local),
-	atomic_list_concat([NS,Local], Strategy),
-	\+ rdf_graph(Strategy),
-	!.
-new_reference_name(Reference) :-
-	setting(amalgame:default_publish_namespace, NS),
-	reset_gensym(reference_alignment),
-	repeat,
-	gensym(reference_alignment, Local),
-	atomic_list_concat([NS,Local], Reference),
-	\+ rdf_graph(Reference),
-	!.
-
-cp_strategy_from_tmp(Request, TmpGraph) :-
-	rdf(Strategy, rdf:type, amalgame:'AlignmentStrategy', TmpGraph),!,
-	cp_graph(TmpGraph, Strategy, true),
-	rdf_unload_graph(TmpGraph),
-	build_redirect(Request, [Strategy]).
-
-build_redirect(Request, [Strategy|_]) :-
-	http_link_to_id(http_ag_build, [strategy(Strategy)], Redirect),
-	http_redirect(moved, Redirect, Request).
-
-delete_redirect(Request, Strategies) :-
-	authorized(write(default, _)),
-	forall(member(Strategy, Strategies),
-	       (   (   provenance_graph(Strategy, Prov)
-		   ->  rdf_unload_graph(Prov)
-		   ;   true
-		   ),
-		   rdf_unload_graph(Strategy)
-	       )
-	      ),
-	http_link_to_id(http_amalgame_main_page, [], Redirect),
-	http_redirect(moved, Redirect, Request).
-
-merge_redirect(Request, Strategies) :-
-	% Create comment
-	maplist(scheme_label, Strategies, Labeled),
-	keysort(Labeled, Sorted),
-	pairs_keys(Sorted, Labels),
-	atomic_list_concat(Labels, ', ', LabelsAtom),
-	atomic_concat('Strategy merged from ', LabelsAtom, Comment),
 
-	% Create merged strategy
-	new_strategy(New, [comment(Comment)]),
-	cp_graphs(Strategies, New),
-	merge_strategy_nodes(Strategies, New),
 
-	% Redirect to builder
-	http_link_to_id(http_ag_build, [strategy(New)], Redirect),
-	http_redirect(moved, Redirect, Request).
 
-merge_strategy_nodes([], _New) :- !.
-merge_strategy_nodes([H|T], New) :-
-	findall(rdf(H,P,O),
-		rdf(H,P,O,New),
-		Triples),
-	forall(member(rdf(_,P,O), Triples),
-	       rdf_assert(New,P,O,New)),
-	merge_strategy_nodes(T, New).
 
-cp_graphs([], _Target) :- !.
-cp_graphs([Head|Tail], Target) :-
-	cp_graph(Head, Target, false),
-	cp_graphs(Tail, Target).
 
-cp_graph(Source, Target, true) :-
-	rdf_unload_graph(Target), % Delete old graphs under the same name
-	cp_graph(Source, Target, false).
 
-cp_graph(Source, Target, false) :-
-	findall(rdf(S,P,O), rdf(S,P,O,Source), Triples),
-	forall(member(rdf(S,P,O), Triples),
-	       rdf_assert(S,P,O,Target)).
diff --git a/components/amalgame/startpage.pl b/components/amalgame/startpage.pl
new file mode 100644
index 0000000..d01b08f
--- /dev/null
+++ b/components/amalgame/startpage.pl
@@ -0,0 +1,318 @@
+:- module(ag_component_startpage,
+	  [ html_new//1, % +Schemes
+	    html_open//1, % +Strategies
+	    html_publish//1, % +Strategies
+	    html_reference//0,
+	    html_import//0
+	  ]).
+
+:- use_module(library(option)).
+:- use_module(library(semweb/rdf_db)).
+:- use_module(library(http/http_dispatch)).
+:- use_module(library(http/html_head)).
+:- use_module(library(http/html_write)).
+
+:- use_module(library(semweb/rdf_label)).
+:- use_module(components(label)).
+
+:- use_module(library(amalgame/util)).
+:- use_module(library(amalgame/voc_stats)).
+:- use_module(components(amalgame/util)).
+
+html_new([]) -->
+	html_acc_item(new,
+		      'new alignment strategy: no (SKOS) vocabularies found',
+		      div([style('padding: 1%')],[
+			  'Please use the Repository drop-down menu to load ',
+			  'the vocabularies you would like to align ',
+			  'into the repository/triple store.'
+		      ]),
+		      [active]
+		     ).
+
+html_new(Schemes) -->
+	{ has_write_permission, !,
+	  ButtonsBottom = div(\html_submit('Start')),
+	  length(Schemes, N),
+	  (   N > 7
+	  ->  ButtonsTop = ButtonsBottom
+	  ;   ButtonsTop = div([],[])
+	  )
+	},
+	html_acc_item(new,
+		      'new alignment strategy',
+		      [ form(action(location_by_id(http_ag_form_new_strategy)),
+			     [  ButtonsTop,
+				\html_vocab_table(Schemes),
+				ButtonsBottom
+			     ])
+		      ],
+		      [active]
+		     ).
+
+html_new(_) -->
+	{
+	 http_location_by_id(http_amalgame_main_page, This),
+	 http_link_to_id(cliopatria_openid:login_page,
+			 ['openid.return_to'(This)], Login)
+	},
+	html_acc_item(new,
+		      'please login to access other functions',
+		      [
+			  div(a([class(login), href(Login)], ['login']))
+		      ],
+		      [inactive]
+		     ).
+
+%%	html_open(+Alignments)
+%
+%
+html_open([]) -->
+	html_acc_item(open,
+		      div([style('font-style: italic; color: gray')],
+			  'no strategies have been created yet'),
+		      [],
+		      [inactive]),
+	!.
+html_open(Strategies) -->
+	{ ButtonsBottom = div([ \html_submit('View selected'),
+			  \html_submit('Merge selected'),
+			  \html_submit('Delete selected')
+			]),
+	  length(Strategies, N),
+	  (   N > 7
+	  ->  ButtonsTop = ButtonsBottom
+	  ;   ButtonsTop = div([],[])
+	  )
+	},
+	html_acc_item(open,
+		      'edit/delete pre-loaded alignment strategy',
+		      [ form(action(location_by_id(http_ag_form_select_strategy)),
+			     [
+				 ButtonsTop,
+				 \html_strategy_table(Strategies,
+						       [linkto(http_ag_build)]),
+				 ButtonsBottom
+
+			     ])
+		      ],
+		      [active]
+		     ).
+html_publish([]) -->
+	html_acc_item(open,
+		      div([style('font-style: italic; color: gray')],
+			  'no mappings have been created yet'),
+		      [],
+		      [inactive]),
+	!.
+html_publish(Strategies) -->
+	{
+	 has_write_permission,
+	 L=http_ag_publish_form,
+	 !
+	},
+	html_acc_item(publish,
+		      'publish alignment strategy results',
+		      [ form(action(location_by_id(L)),
+			     [ \html_strategy_table(Strategies, [linkto(L)]),
+			       \html_submit('Publish')
+			     ])
+		      ],
+		      [inactive]).
+html_publish(_) -->  !.
+
+
+html_reference -->
+	{ has_write_permission,
+	  !
+	},
+	html_acc_item(reference,
+		      'upload existing/reference alignment',
+		      form([action(location_by_id(http_ag_form_upload_reference)),
+			    method('POST'),
+			    enctype('multipart/form-data') ],
+			   [ p(['Upload an exisiting alignment to build upon, ',
+				'or to use as reference (ground truth)' ]),
+			     input([type(file), name(data),
+				    size(50), autocomplete(off)
+				   ]),
+			     input([type(submit), value('Upload')])
+			   ]),
+		      [inactive]
+		     ).
+
+html_reference --> !.
+
+html_import -->
+	{
+	 has_write_permission,
+	 !
+	},
+	html_acc_item(import,
+		      'upload strategy or clone execution trace',
+		      [ form([action(location_by_id(http_ag_form_upload_strategy_resource)),
+			      method('POST')
+			     ],
+			     [ 'URL: ',
+			       input([type(text), name(url), value('http://'),
+				      autocomplete(off), size(50)
+				     ]),
+			       input([type(submit), value('Upload')])
+			   ]),
+			form([action(location_by_id(http_ag_form_upload_strategy_data)),
+			      method('POST'),
+			      enctype('multipart/form-data')
+			     ],
+			     [ 'File: ',
+			       input([type(file), name(data),
+				      size(50)%, autocomplete(off)
+				     ]),
+			       input([type(submit), value('Upload')])
+			     ])
+		      ],
+		      [inactive]).
+
+html_import --> !.
+
+/* Helper rules to implement the stuff above: */
+
+html_vocab_table(Vs) -->
+	html([
+	    \html_requires(sortable),
+	    table([class(sortable)],
+		   [thead(tr(\html_vocab_head)),
+		    tbody(\html_vocab_rows(Vs))
+		   ])
+	]).
+
+html_vocab_head -->
+	html([th([]),
+	      th(class(name),       name),
+	      th(class(version),    version),
+	      th(class(count),     'estimated #concepts'),
+	      th(class(preflangs), 'prefLabels'),
+	      th(class(altlangs),  'altLabels')
+	     ]).
+
+html_vocab_rows([]) --> !.
+html_vocab_rows([Scheme|Vs]) --> {
+    (   voc_property(Scheme, numberOfConcepts(ConceptCount), [compute(false)])
+    ->  true
+    ;   rdf_estimate_complexity(_, skos:inScheme, Scheme, ConceptCount)
+    ),
+    voc_property(Scheme, languages(skos:prefLabel, PrefLangs)),
+    voc_property(Scheme, languages(skos:altLabel, AltLangs)),
+    voc_property(Scheme, version(Version0)),
+    (	Version0 == ''
+    ->	voc_property(Scheme, revision(Version))
+    ;	Version = Version0
+    )
+},
+	html(tr([td(input([type(checkbox), autocomplete(off), class(option),
+			   name(scheme), value(Scheme)])),
+		 td(class(name),    \html_scheme_name(Scheme)),
+		 td(class(version), Version),
+		 td(class(count), ConceptCount),
+		 td([span(class(preflangs), \html_showlist(PrefLangs))]),
+		 td([span(class(altlangs),  \html_showlist(AltLangs) )])
+
+		])),
+	html_vocab_rows(Vs).
+
+
+
+
+%%	html_strategy_table(+Graphs, +Options)
+%
+%	Emit HTML table with strategy graph properties.
+
+html_strategy_table(Strategies, Options) -->
+	html([
+	    \html_requires(sortable),
+	    table(
+		[class(sortable)],
+		[ thead(tr(\html_alignment_head)),
+		  tbody(\html_alignment_rows(Strategies, Options))
+		])
+	]).
+
+html_alignment_head -->
+	html([th([]),
+	      th(name),
+	      th(includes),
+	      th('Created by:'),
+	      th('Comment:')
+	     ]).
+
+html_alignment_rows([],_) --> !.
+html_alignment_rows([URI-Schemes|Gs], Options) -->
+	{
+	 (   rdf(URI, dcterms:creator, Author, URI)
+	 ->  true
+	 ;   Author = anonymous
+	 ),
+	 (   rdf(URI, rdfs:comment, CommentR, URI)
+	 ->  literal_text(CommentR, Comment)
+	 ;   Comment = ''
+	 )
+	},
+	html(tr([td(input([type(checkbox), autocomplete(off), class(option), name(strategy), value(URI)])),
+		 td(\html_strategy_name(URI, Options)),
+		 td(\html_scheme_labels(Schemes)),
+		 td(\turtle_label(Author)),
+		 td([class(comment)],Comment)
+		])),
+	html_alignment_rows(Gs, Options).
+
+html_scheme_labels([]) --> !.
+html_scheme_labels([S|Ss]) -->
+	html(div(\turtle_label(S))),
+	html_scheme_labels(Ss).
+
+html_strategy_name(Graph, Options) -->
+	{ rdf_graph_label(Graph, Label),
+	  option(linkto(LinkTo), Options, http_ag_build),
+	  http_link_to_id(LinkTo, [strategy(Graph)], Link)
+	},
+	html(a([href(Link)],Label)).
+
+html_scheme_name(Graph) -->
+	{ rdf_graph_label(Graph, Label),
+	  http_link_to_id(http_skos_browser, [scheme(Graph)], Link)
+	},
+	html(a([href(Link)],Label)).
+
+
+%%	html_submit(+Label)
+%
+%
+
+html_submit(Label) -->
+	html(span(class(controls),
+		 [ input([type(submit), autocomplete(off), class(start),
+			  name(submit), disabled(true), value(Label)])
+		 ])).
+
+
+%%	html_acc_item(+Id, +Label, +HTMLBody, +Options)
+%
+%	Emit html markup for a YUI3 accordion item.
+%	Options:
+%
+%	* active/inactive
+
+html_acc_item(Id, Label, Body, Options) -->
+	{ (   option(active, Options)
+	  ->  Class = 'yui3-accordion-item yui3-accordion-item-active'
+	  ;   Class = 'yui3-accordion-item'
+	  )
+	},
+	html(div([class(Class), id(Id)],
+		 [ div(class('yui3-accordion-item-hd'),
+		       a([href('javascript:{}'), class('yui3-accordion-item-trigger')],
+			   Label)),
+		   div(class('yui3-accordion-item-bd'),
+		       Body)
+		 ])).
+
+
diff --git a/lib/amalgame/rdf_util.pl b/lib/amalgame/rdf_util.pl
new file mode 100644
index 0000000..041dfe4
--- /dev/null
+++ b/lib/amalgame/rdf_util.pl
@@ -0,0 +1,34 @@
+:- module(ag_rdf_util, [
+	      cp_graphs/2,
+	      cp_graph/3
+	  ]).
+
+:- use_module(library(lists)).
+:- use_module(library(semweb/rdf_db)).
+
+
+%%	cp_graphs(+GraphList, Target) is det.
+%
+%	Copy all triples in the named graphs in GraphList to the named
+%	graph Target.
+
+cp_graphs([], _Target) :- !.
+cp_graphs([Head|Tail], Target) :-
+	cp_graph(Head, Target, false),
+	cp_graphs(Tail, Target).
+
+%%	cp_graph(+Source, +Target, +Overwrite) is det.
+%
+%	Copy all triples from Source to Target.
+%	If Overwrite is true, existing triples in Target are removed
+%	first.
+
+cp_graph(Source, Target, true) :-
+	rdf_unload_graph(Target), % Delete old graphs under the same name
+	cp_graph(Source, Target, false).
+
+cp_graph(Source, Target, false) :-
+	findall(rdf(S,P,O), rdf(S,P,O,Source), Triples),
+	forall(member(rdf(S,P,O), Triples),
+	       rdf_assert(S,P,O,Target)).
+
diff --git a/lib/amalgame/util.pl b/lib/amalgame/util.pl
index 4e7b891..7cb3171 100644
--- a/lib/amalgame/util.pl
+++ b/lib/amalgame/util.pl
@@ -1,6 +1,7 @@
 :- module(ag_utils,
 	  [   mint_node_uri/3,
 	      amalgame_strategy_schemes/2,
+	      amalgame_alignable_schemes/1,
 
 	      js_mappings_metadata/3,
 	      js_focus_node/3,
@@ -8,6 +9,7 @@
 
 	      rdf_lang/3,
 	      rdf_lang/4,
+	      rdf_graph_label/2,
 
 	      assert_user_provenance/2,
 
@@ -38,6 +40,7 @@
 :- use_module(library(amalgame/ag_stats)).
 :- use_module(library(amalgame/ag_reference)).
 :- use_module(library(amalgame/ag_evaluation)).
+:- use_module(library(amalgame/voc_stats)).
 
 :- multifile
 	ag:menu_item/2.
@@ -64,6 +67,31 @@ mint_node_uri(Strategy, Type, URI) :-
 	\+ rdf_graph(URI),
 	!.
 
+%%	amalgame_alignable_schemes(-Schemes) is det.
+%
+%	Schemes is unified with a sorted list of urls of
+%	skos:ConceptSchemes or other alignable objects.
+%
+%	Sorting is based on case insensitive scheme labels.
+
+amalgame_alignable_schemes(Schemes) :-
+	findall(C,
+		(   is_vocabulary(C),
+		    voc_property(C, virtual(false))
+		),
+		All),
+	maplist(scheme_label, All, Labeled),
+	keysort(Labeled, Sorted),
+	pairs_values(Sorted, Schemes).
+
+scheme_label(URI, Key-URI) :-
+	rdf_graph_label(URI, CasedKey),
+	downcase_atom(CasedKey, Key).
+
+rdf_graph_label(Graph, Label) :-
+	rdf_display_label(Graph, Lit),
+	literal_text(Lit, Label),!.
+rdf_graph_label(Graph, Graph).
 
 my_atom_json_dict(Json, Dict, Options) :-
 	var(Dict),!,
@@ -168,8 +196,21 @@ mapping_metadata(Strategy, M, _) :-
 
 js_focus_node(Strategy, URI, NodeProps) :-
 	findall(Type-Value, node_prop(Strategy, URI, Type, Value), Pairs),
-	dict_pairs(NodeProps, node, Pairs).
+	group_pairs_by_key_if_needed(Pairs, Grouped),
+	dict_pairs(NodeProps, node, Grouped).
+
+group_pairs_by_key_if_needed([], []).
+group_pairs_by_key_if_needed([M-N|T0], [M-Result|T]) :-
+	same_key(M, T0, TN, T1),
+	(   TN == []
+	->  Result = N
+	;   Result = [N|TN]
+	),
+	group_pairs_by_key_if_needed(T1, T).
 
+same_key(M, [M-N|T0], [N|TN], T) :- !,
+	same_key(M, T0, TN, T).
+same_key(_, L, [], L).
 %%	js_strategy_nodes(+Strategy, -Nodes)
 %
 %	Nodes contains all nodes in alignment Strategy with their type
@@ -193,7 +234,8 @@ graph_resource(Graph, R) :-
 
 node_data(Strategy, R, R-Props) :-
 	findall(Type-Value, node_prop(Strategy, R, Type, Value), Pairs),
-	dict_pairs(Props, node, Pairs).
+	group_pairs_by_key_if_needed(Pairs, Grouped),
+	dict_pairs(Props, node, Grouped).
 
 node_prop(_, R, uri, R).
 node_prop(S, R, label, Label) :-