yaz/commit

ongoing conversion to new data model

authorMichiel Hildebrand
Wed Feb 2 16:23:33 2011 +0100
committerMichiel Hildebrand
Wed Feb 2 16:23:33 2011 +0100
commit0859f6f0378d1af5dd36945d80094145577e6f76
tree30f054a51b6b14f982cf3ca07f742c0eed4ad5ba
parent0a03b05d1f7278aaf280f436b83c0a3e9a101556
Diff style: patch stat
diff --git a/applications/yaz_game.pl b/applications/yaz_game.pl
index 613068e..02a538d 100644
--- a/applications/yaz_game.pl
+++ b/applications/yaz_game.pl
@@ -80,13 +80,12 @@ http_yaz_game(Request) :-
 	    nonvar(URL)
 	->  create_game(URL, User, Game, [video(Video),title(Title)]),
 	    html_waiting_page(Game, URL, User)
-	;   setting(match_interval, Interval),
-	    join_game(Game, User),
+	;   join_game(Game, User),
 	    game_video_start(Game, URL, PlayHead),
 	    PlayerObj = {player:P, name:Name, score:Score},
 	    findall(PlayerObj, active_player(Game, P, Name, Score), Players),
-	    TagObj = json([tag=Tag, label=Label, match=Match, type=Type, order=Order]),
-	    findall(Time-TagObj, user_annotation(Game, User, Interval, Tag, Label, Time, Type, Match, Order), Tags0),
+	    TagObj = json([annotation=A, label=Tag, time=Time, match=Match]),
+	    findall(Time-TagObj, user_tag(Game, User, A, Tag, Time, Match), Tags0),
 	    keysort(Tags0, Tags1),
 	    reverse(Tags1, Tags2),
 	    pairs_values(Tags2, Tags),
@@ -299,17 +298,16 @@ html_page_yui(Game, URL, User, PlayHead, Players, Tags) -->
 						 })),
 		  \js_support_functions(Game, User, DataServer),
 		  \js_call('Y.later'(RequestInterval, symbol('Y'),
-				     symbol(fetchData), symbol({}), symbol(true))),
+				     symbol(fetchData), symbol(null), symbol(true))),
 		  \js_call('videoPlayer.render'('#videoplayer')),
 		  \js_input_method
  		]).
 
 js_support_functions(Game, User, DataServer) -->
-	js_function_decl(fetchData, [tag],
+	js_function_decl(fetchData, [e],
 			 \[
 '   var data = {game:"',Game,'",user:"',User,'",playhead:videoPlayer.getTime()*1000};
-    if(tag.label) {data.tag = tag.label}
-    if(tag.uri) {data.taguri = tag.uri}
+    if(e) {data.tag=e.label;}
     Y.io("',DataServer,'", {data: data,
 			    on: {success:handleResponse}
 			   });\n'
@@ -317,9 +315,9 @@ js_support_functions(Game, User, DataServer) -->
 
 	js_function_decl(handleResponse, [id, o],
 			 \[
-'    var data = Y.JSON.parse(o.responseText);
-    gamePlayers.updatePlayers(data.players);
-    gameInput.updateTags(data.tags);\n'
+'    var r = Y.JSON.parse(o.responseText);
+    gamePlayers.updatePlayers(r.players);
+    gameInput.updateTags(r.tags);\n'
 			  ]).
 
 js_input_method -->
@@ -375,7 +373,8 @@ create_game(URL, Player, Game, _Options) :-
 create_game(URL, Player, Game, Options) :-
 	option(video(Video), Options, _),
 	option(title(Title), Options, _),
-   	create_user_process([rdf:type=pprime:'Game',
+   	create_user_process(Player,
+			    [rdf:type=pprime:'Game',
 			     opmv:used=URL
 			    ], Game),
 	new_player_score(Game, Player),
@@ -415,7 +414,7 @@ game_video_start(_Game, '', 0). % for testing
 join_game(Game, Player) :-
  	(   user_process_joined(Game, Player)
 	->  set_active_process(Game)
-	;   join_user_process(Game),
+	;   join_user_process(Game, Player),
 	    debug(game, 'Game ~w joined by ~w', [Game, Player]),
 	    new_player_score(Game, Player)
 	).
@@ -430,34 +429,16 @@ quit_game(Game, Player) :-
 	left_game(Game, Player),
 	!.
 quit_game(Game, Player) :-
-	debug(game, 'Quit game ~w by ~w', [Game, Player]),
-	get_time(Time),
-	rdf_bnode(QuitEvent),
-	player_score(Game, Player, Score),
-	rdf_transaction(assert_quit_event(QuitEvent, Game, Player, Score, Time)),
-	retractall(player_score(Game, Player, Score)),
-	debug(game, 'Game quit with event ~w', [QuitEvent]).
-
-assert_quit_event(ID, Game, Player, Score, Time) :-
-	get_time(Time),
-	rdf_assert(ID, sem:subEventOf, Game, Game),
-	rdf_assert(ID, rdf:type, pprime:'QuitGame', Game),
-	rdf_assert(ID, sem:hasActor, Player, Game),
-	rdf_assert(ID, sem:timeStampedAt, literal(Time), Game),
-	rdf_assert(ID, pprime:finalScore, literal(Score), Game).
-
-
-%%	add_tag(+Game, +Player, +Tag, +TagURI, +PlayHeadTime)
+	debug(game, 'Quit game ~w by ~w', [Game, Player]).
+
+
+%%	add_tag(+Game, +Player, +Tag, +PlayHeadTime, -AnnotationId)
 %
 %	Asserts that User has entered a Tag.
 
-add_tag(Game, Player, TagLabel, TagURI, PlayHead) :-
+add_tag(Game, Player, Tag, PlayHead, AnnotationId) :-
 	rdf(Game, opmv:used, URL),
-	(   nonvar(TagURI)
-	->  Tag = TagURI
-	;   Tag = TagLabel
-	),
-	create_video_annotation(URL, literal(Tag), PlayHead, Player, AnnotationId),
+ 	create_video_annotation(URL, literal(Tag), PlayHead, Player, AnnotationId),
 	debug(game, 'Added tag ~w at time ~w by ~w (~w)', [Tag, PlayHead, Player, AnnotationId]).
 
 %%	active_player(+Game, -Player, -Name, Score)
@@ -478,86 +459,51 @@ left_game(Game, Player) :-
  	rdf(QuitEvent, sem:hasActor, Player, Game).
 
 
-%%	user_annotation(+Game, +User, +Interval, -Tag, -Time, -Type,
-%%	-Match, -Order)
+%%	user_tag(+Game, +User, -Annotation, -Tag, -Match)
 %
 %	Tag is entered by User during Game.
 
-user_annotation(Game, User, Interval, Tag, Label, Time, Type, Match, Order) :-
+user_tag(Game, User, Annotation, Tag, Time, Match) :-
  	rdf(Annotation, pprime:creator, User, Game),
-	rdf(Annotation, rdf:value, TagTerm),
-	rdf(Annotation, pprime:videoPlayhead, Time0),
-	literal_to_number(Time0, Time),
-	tag_type(TagTerm, Type, Tag, Label),
- 	matching_type(Game, User, TagTerm, Time, Interval, Match, Order).
+	rdf(Annotation, rdf:value, literal(Tag)),
+	rdf(Annotation, pprime:videoPlayhead, literal(Time), _),
+	matched_json_term(Annotation, Match).
 
-tag_type(literal(Tag), literal, Tag, Tag) :- !.
-tag_type(Tag, uri, Tag, Label) :-
-	rdf(Tag, rdfs:label, literal(Label)).
+matched_json_term(Annotation, json([type=Match, score=Score, order=Order])) :-
+	rdf(Annotation, pprime:match, literal(Match)),
+	!,
+	rdf(Annotation, pprime:score, literal(Score)),
+	rdf(Annotation, pprime:order, literal(Order)).
+matched_json_term(_,  @false).
 
-%%	user_matched_tag(+Game, +User, +PlayHead, +Interval, -Tag,
-%%	-Label, -Type, -Match, Order)
+%%	user_matched_tag(+Game, +User, +PlayHead, +Interval,
+%%	-Annotation, -Match, -Score)
 %
 %	Tag is entered by User during Game.
 
-user_matched_tag(Game, User, PlayHead, Interval, Tag, Label, Type, Match, Order) :-
-	rdf(Annotation, pprime:creator, User, Game),
-	rdf(Annotation, pprime:videoPlayhead, literal(Time0), Game),
-	literal_to_number(Time0, Time),
-	Time > PlayHead-Interval,
-	rdf(Annotation, rdf:value, TagTerm, Game),
-	tag_type(TagTerm, Type, Tag, Label),
-	matching_type(Game, User, TagTerm, Time, Interval, Match, Order),
-	Match \== @false.
-
-%%	matching_type(+Game, +User, +Tag, +Time, +Interval, -MatchType,
-%%	-Order)
-%
-%	Matchtype is one of [....] indicating how Tag can be matched.
-
-matching_type(Game, User, Tag, Time, Interval, MatchType, Order) :-
-	match_existing_tags(Game, User, Tag, Time, Interval, Matches),
-	(   Matches = []
-	->  MatchType = @false,
-	    Order = 0
-	;   user_best_match(Matches, MatchType),
-	    tag_order(Matches, 1, Order)
- 	).
-
-tag_order([], N, N).
-tag_order([match(_, _, Diff, _)|_T], N, N) :-
-	Diff =< 0, !.
-tag_order([_|T], N0, N) :-
-	N1 is N0+1,
-	tag_order(T, N1, N).
-
-%%	tag_match(+Game, +User, +Tag, +Time, +Interval, -Player,
-%%	-Diff)
+user_matched_tag(Game, User, Playhead, Interval, Annotation, Match) :-
+	Start is Playhead-Interval,
+  	rdf(Annotation, pprime:videoPlayhead, literal(between(Start,Playhead), _), Game),
+	rdf(Annotation, pprime:creator, User),
+	matched_json_term(Annotation, Match).
+
+%%	tag_match(+Game, +User, +Tag, +VideoTime, +Interval,
+%%	-Annotation, -Player, -Diff)
 %
 %	Returns players that entered the same Tag within Interval of
 %	Time.
 
-tag_match(Game, User, Tag, PlayHead, Interval, Player, Diff, exact, Type) :-
-	matching_annotation(Game, Tag, Annotation, Type),
- 	rdf(Annotation, pprime:videoPlayhead, literal(Time0), Game),
+match_tag(Game, User, Tag, Playhead, Interval, Annotation, Player, Match, Diff) :-
+	Start is Playhead-Interval,
+	tag_match_(Tag, Game, Annotation, Match),
+  	rdf(Annotation, pprime:videoPlayhead, literal(between(Start,Playhead), Time0)),
+	rdf(Annotation, pprime:creator, Player),
+	User \== Player,
 	literal_to_number(Time0, Time),
-	Diff is PlayHead-Time,
-	Interval >= abs(Diff),
-	rdf(Annotation, pprime:creator, Player, Game),
-	User \== Player.
-
-matching_annotation(Game, Tag, Annotation, Type) :-
-	rdf(Annotation, rdf:value, Tag, Game),
-	(   Tag = literal(_)
-	->  Type = literal
-	;   Type = uri
-	).
-matching_annotation(Game, literal(Tag), Annotation, uri) :- !,
-	rdf(Annotation, rdf:value, TagURI, Game),
-	rdf(TagURI, rdfs:label, literal(exact(Tag),_)).
-matching_annotation(Game, TagURI, Annotation, literal) :-
-	rdf(TagURI, rdfs:label, literal(Tag)),
-	rdf(Annotation, sem:involves, literal(exact(Tag),_), Game).
+	Diff is Playhead-Time.
+
+tag_match_(Tag, Game, Annotation, exact) :-
+	rdf(Annotation, rdf:value, literal(Tag), Game).
 
 
 :- http_handler(yaz('gamedata'), http_game_data, []).
@@ -576,88 +522,66 @@ http_game_data(Request) :-
 				[number, description('Current time of the video play head (in miliseconds)')]),
 			   tag(Tag,
 			       [optional(true),
-				description('Optionally a new tag can be added')]),
-			   taguri(TagURI,
-				  [optional(true),
-				   description('Optionally the new tag can have a URI')])
+				description('Optionally a new tag can be added')])
 			]),
 	setting(match_interval, Interval),
 	(   nonvar(Tag)
- 	->  add_tag(Game, User, Tag, TagURI, Playhead),
-	    update_scores(Game, User, Tag, TagURI, Playhead, Interval)
-	;   true
+ 	->  add_tag(Game, User, Tag, Playhead, AnnotationId),
+	    match_existing_tags(Game, User, Tag, Playhead, Interval, Matches),
+	    update_scores(Matches, AnnotationId, Game, User)
+ 	;   true
 	),
-
 	PlayerObj = json([player=P, name=Name, score=Score]),
 	findall(PlayerObj,
 		active_player(Game, P, Name, Score),
 		Players),
 
-	TagObj = json([tag=T, label=L, type=Type, match=Match, order=Order]),
+	TagObj = json([annotation=A, match=Match]),
 	findall(TagObj,
-		user_matched_tag(Game, User, Playhead, Interval, T, L, Type, Match, Order),
+		user_matched_tag(Game, User, Playhead, Interval, A, Match),
 		Tags),
 
 	reply_json(json([user=User, players=Players, tags=Tags])).
 
 
-%%	update_scores(+Game, +User, +Tag, +TagURI, +Playhead, +Interval)
-%
-%	Find matching tags within interval of PlayHead and update player
-%	scores.
-
-update_scores(Game, User, TagL, TagURI, Playhead, Interval) :-
-	(   nonvar(TagURI)
-	->  Tag = TagURI,
-	    Type = uri
-	;   Tag = literal(TagL),
-	    Type = literal
-	),
-	match_existing_tags(Game, User, Tag, Playhead, Interval, Matches),
-	(   Matches = []
-	->  true
-	;   length(Matches, C0),
-	    Total is C0+1,
-	    update_player_scores(Matches, 1, Total, Game),
-	    user_best_match(Matches, Match),
-	    tag_match_points(Match, Type, Total, 0, Total, Points),
-	    update_player_score(Game, User, Points)
- 	).
-
-user_best_match(Matches, Match) :-
-	maplist(user_match, Matches, Pairs0),
-	keysort(Pairs0, Pairs1),
-	reverse(Pairs1, [_Points-Match|_]).
-
-user_match(match(Match,_,_,_), P-Match) :-
-	(   Match = generic
-	->  match_points(specific, P)
-	;   match_points(Match, P)
-	).
-
 %%	match_existing_tags(+Game, +User, +Tag, +Playhead, +Interval,
 %%	-Matches)
 %
 %	Returns all matching tag within Interval of Playhead
 
 match_existing_tags(Game, User, Tag, Playhead, Interval, Matches) :-
-	findall(Diff-match(Match, Type, Diff, Player),
-		tag_match(Game, User, Tag, Playhead, Interval, Player, Diff, Match, Type),
+	findall(Diff-match(Annotation, Player, Match, Diff),
+		match_tag(Game, User, Tag, Playhead, Interval, Annotation, Player, Match, Diff),
 		Matches0),
 	keysort(Matches0, Matches1),
 	reverse(Matches1, Matches2),
 	pairs_values(Matches2, Matches).
 
-%%	update_players_scores(+Matches, +EntryOrder, +TotalMatches,
-%%	+Game)
+
+%%	update_scores(+Matches, +Annotation, +Game, +User)
 %
-%	Compute the scores for each player in Matches and update
-%	their score according to the type of Match.
+%	Find matching tags within interval of PlayHead and update player
+%	scores.
+
+update_scores([], _, _, _) :- !.
+update_scores(Matches, Annotation, Game, User) :-
+	length(Matches, C0),
+	Total is C0+1,
+	% score of newly added tag
+	maplist(user_match_points, Matches, Pairs0),
+	keysort(Pairs0, Pairs1),
+	reverse(Pairs1, [_-Match|_]),
+ 	tag_match_points(Match, Total, 0, Total, Points),
+	rdf_transaction(assert_match(Annotation, Game, Match, Points, Total)),
+	update_player_score(Game, User, Points),
+	% scores of other matches
+	rdf_transaction(update_player_scores(Matches, 1, Total, Game)).
 
 update_player_scores([], _, _, _).
-update_player_scores([match(Match,Type,Diff,Player)|Ms], N, Count, Game) :-
+update_player_scores([match(Annotation,Player,Match,Diff)|Ms], N, Count, Game) :-
 	N1 is N + 1,
-  	tag_match_points(Match, Type, N, Diff, Count, Points),
+  	tag_match_points(Match, N, Diff, Count, Points),
+	assert_match(Annotation, Game, Match, Points, N),
 	update_player_score(Game, Player, Points),
 	update_player_scores(Ms, N1, Count, Game).
 
@@ -667,13 +591,17 @@ update_player_score(Game, Player, Points) :-
 	NewScore is OldScore+Points,
 	assert(player_score(Game, Player, NewScore)).
 
-tag_match_points(Match, Type, Order, _Diff, _Total, Points) :-
+user_match_points(match(_,_,Match,_), Points-Match) :-
+	(   Match = generic
+	->  match_points(specific, Points)
+	;   match_points(Match, Points)
+	).
+
+tag_match_points(Match, Order, _Diff, _Total, Points) :-
 	match_points(Match, MatchPoints),
-	type_points(Type, TypePoints),
-	Points0 is MatchPoints + TypePoints,
- 	(   Order = 1
-	->  Points is Points0*2
-	;   Points = Points0
+  	(   Order = 1
+	->  Points is MatchPoints*2
+	;   Points = MatchPoints
 	).
 
 match_points(exact, 50).
@@ -682,8 +610,10 @@ match_points(specific, 100).
 match_points(generic, 20).
 match_points(related, 20).
 
-type_points(uri, 50).
-type_points(literal, 0).
+assert_match(Annotation, Game, Match, Score, Order) :-
+	rdf_assert(Annotation, pprime:match, literal(Match), Game),
+	rdf_assert(Annotation, pprime:score, literal(Score), Game),
+	rdf_assert(Annotation, pprime:order, literal(Order), Game).
 
 
 :- http_handler(yaz('waitingdata'), http_waiting_data, []).
diff --git a/applications/yaz_game_recap.pl b/applications/yaz_game_recap.pl
index 09e008f..0c59789 100644
--- a/applications/yaz_game_recap.pl
+++ b/applications/yaz_game_recap.pl
@@ -34,13 +34,14 @@
 %	of it.
 
 http_yaz_game_recap(Request) :-
-	ensure_logged_on(_),
+	ensure_logged_on(User0),
+	user_property(User0, url(User)),
 	http_parameters(Request,
 			[ video(Video,
 				[description('Current video')]),
 			  process(Process,
 			       [optional(true), desription('When set only annotations within this process are shown')]),
-			  user(User,
+			  user(Player,
 				[optional(true), description('When set only annotations created by this user are shown')]),
 			  interval(Interval,
 				   [default(0), number,
@@ -55,11 +56,11 @@ http_yaz_game_recap(Request) :-
 				[default(0),description('Start time of the video')])
 			]),
 	Options = [process(Process),
-		   user(User),
+		   user(Player),
 		   interval(Interval),
 		   confirmed(Confirmed)
 		  ],
-	create_user_process([rdf:type=pprime:'GameRecap',
+	create_user_process(User, [rdf:type=pprime:'GameRecap',
 			     opmv:used=Video
 			    ], _Process),
 	video_annotations(Video, Annotations0, Options),
diff --git a/applications/yaz_mgarden.pl b/applications/yaz_mgarden.pl
index 6c428bc..5670cc9 100644
--- a/applications/yaz_mgarden.pl
+++ b/applications/yaz_mgarden.pl
@@ -28,6 +28,11 @@
 
 :- http_handler(yaz(mgarden), http_yaz_mgarden, []).
 :- http_handler(yaz('data/confirmmatch'), http_yaz_api_confirm_match, []).
+:- http_handler(yaz('data/mgarden'), http_yaz_api_mgarden_data, []).
+
+
+:- setting(request_interval, integer, 2000,
+	   'Interval between requests to the server (in miliseconds)').
 
 %%	http_yaz_mgarden(+Request)
 %
@@ -35,47 +40,57 @@
 %	of it.
 
 http_yaz_mgarden(Request) :-
-	ensure_logged_on(_),
+	ensure_logged_on(User0),
+	user_property(User0, url(CurrentUser)),
 	http_parameters(Request,
 			[ video(Video,
 				[description('Current video')]),
 			  process(Process,
 			       [optional(true), desription('When set only annotations within this process are shown')]),
 			  user(User,
-				[optional(true), description('When set only annotations created by this user are shown')])
+				[default(CurrentUser),
+				 description('When set only annotations created by this user are shown')])
   			]),
 	Options = [process(Process),
 		   user(User)
   		  ],
-	create_user_process([rdf:type=pprime:'mgarden',
-			     opmv:used=Video
-			    ], _Process),
+	create_user_process(CurrentUser, [rdf:type=pprime:'mgarden',
+				   opmv:used=Video
+				  ], _Process),
 	video_annotations(Video, As0, Options),
 	sort_by_arg(As0, 2, As),
 	tag_matches(As, User, Process, 10000, Annotations),
- 	html_video_page(Video, Annotations, 0, Options).
+ 	html_video_page(Video, CurrentUser, Annotations, 0, Options).
 
 tag_matches([], _, _, _, []).
 tag_matches([A0|As], User, Process, Interval, [A|Rest]) :-
 	A0 = annotation(Value,Start,End,Entries),
 	A =  annotation(Value,Start,End,Entries,Match),
-	(   tag_match(Value, Start, User, Process, Interval, Match)
+	(   existing_match(Entries, Match)
+	->  true
+	;   tag_match(Value, Start, User, Process, Interval, Match)
 	->  true
 	;   Match = @false
 	),
 	tag_matches(As, User, Process, Interval, Rest).
 
+existing_match(Entries, Match) :-
+	findall(S, (member(E, Entries),
+		    rdf(i(E,_), pprime:score, S)
+		   ),
+		Ss),
+	(   max_list(Ss, Score)
+	->  Match = match(exact, score(Score))
+	;   Match = @false
+	).
 
 tag_match(literal(Tag), Time, User, Game, Interval, Match) :-
-	Match = match(Type, E, literal(Tag1)),
+	Match = match(Type, 0, E, literal(Tag1)),
 	snowball(english, Tag, Stem0),
 	downcase_atom(Stem0, Stem),
 	findall(Concept, find_tag_concept(Tag, Concept, _), Cs),
  	tagentry_in_interval(Game, User, Time, Interval, E),
-	(   rdf(E, rdf:value, literal(Tag))
-	->  Type = exact,
-	    Tag1 = Tag
-	;   rdf(E, rdf:value, literal(Tag1)),
+	(   rdf(E, rdf:value, literal(Tag1)),
 	    snowball(english, Tag1, Stem1),
 	    downcase_atom(Stem1, Stem)
 	->  Type = stem
@@ -101,11 +116,12 @@ tagentry_in_interval(Game, User, Time, Interval, E) :-
 
 
 
-%%	html_video_page(+Video, +Annotations, +StartTime, +Options)
+%%	html_video_page(+Video, +User, +Annotations, +StartTime,
+%%	+Options)
 %
 %	Emit an HTML page with a video player and a tag carousel.
 
-html_video_page(Video, Annotations, StartTime, Options) :-
+html_video_page(Video, User, Annotations, StartTime, Options) :-
 	reply_html_page(yaz,
 			[ title(['YAZ - ', Video])
 			],
@@ -113,7 +129,7 @@ html_video_page(Video, Annotations, StartTime, Options) :-
  			  div(class('video-results'),
 			      \html_video_page_containers(Video, Options)),
 			 script(type('text/javascript'),
-				\html_video_page_yui(Video, Annotations, StartTime, Options))
+				\html_video_page_yui(Video, User, Annotations, StartTime, Options))
 			]).
 
 html_video_page_containers(Video, _Options) -->
@@ -126,11 +142,12 @@ html_video_page_containers(Video, _Options) -->
 		   ])
     	     ]).
 
-html_video_page_yui(Video, Annotations, StartTime, _Options) -->
+html_video_page_yui(Video, User, Annotations, StartTime, _Options) -->
 	{ video_source(Video, Src),
  	  http_absolute_location(js('videoplayer/'), FilePath, []),
 	  http_absolute_location(js('videoplayer/videoplayer.js'), VideoPlayer, []),
 	  http_absolute_location(js('tagcarousel/tagcarousel.js'), TagCarousel, []),
+	  setting(request_interval, RequestInterval),
   	  annotation_to_json(Annotations, JSONTags)
    	},
 	html_requires(js('videoplayer/swfobject.js')),
@@ -161,9 +178,27 @@ html_video_page_yui(Video, Annotations, StartTime, _Options) -->
  		  \js_call('videoPlayer.render'('#videoplayer')),
 		  \js_call('tagCarousel.render'('#tagplayer')),
  		  \js_yui3_on(tagCarousel, itemSelect, \js_tag_select),
- 		  \js_yui3_on(tagCarousel, itemConfirm, \js_confirm)
+ 		  \js_yui3_on(tagCarousel, itemConfirm, \js_confirm(User)),
+		  \js_support_functions(User),
+		  \js_call('Y.later'(RequestInterval, symbol('Y'),
+				     symbol(fetchData), symbol({}), symbol(true)))
    		]).
 
+js_support_functions(User) -->
+	{ http_location_by_id(http_yaz_api_mgarden_data, DataServer)
+	},
+	js_function_decl(fetchData, [],
+			 \[
+'   var data = {user:"',User,'"};
+    Y.io("',DataServer,'", {data: data,
+			    on: {success:handleResponse}
+			   });\n'
+			  ]),
+	js_function_decl(handleResponse, [id, o],
+			 \[
+'    var data = Y.JSON.parse(o.responseText);\n'
+			  ]).
+
 js_tag_select -->
 	js_function([e],
 		    \[
@@ -173,7 +208,7 @@ js_tag_select -->
      }\n'
 		    ]).
 
-js_confirm -->
+js_confirm(User) -->
 	{ http_location_by_id(http_yaz_api_confirm_match, ConfirmServer)
 	},
 	js_function([e],
@@ -183,7 +218,8 @@ js_confirm -->
 	 target = e.annotation.match.uri,
 	 match = e.annotation.match.type;\n',
      \js_call('Y.io'(ConfirmServer, {
-				       data:{source:symbol(source),
+				       data:{user:User,
+					     source:symbol(source),
 					     target:symbol(target),
 					     match:symbol(match)},
 				       on:{success:symbol('function(id, o)
@@ -201,9 +237,10 @@ js_confirm -->
 %	Handler for GET submission of a tag modification.
 
 http_yaz_api_confirm_match(Request) :-
- 	ensure_logged_on(_),
-	http_parameters(Request,
-			[ source(Source,
+ 	http_parameters(Request,
+			[ user(User,
+			       [description('URL of the user')]),
+			  source(Source,
 				   [description('URL of source')]),
 			  target(Target,
 			      [description('URL of the target')]),
@@ -212,18 +249,78 @@ http_yaz_api_confirm_match(Request) :-
 			]),
  	debug(yaz(update), 'confirm ~w match between ~w and ~w',
 	      [Match, Source, Target]),
+
+	(   confirmed(Match, Source, Target, User)
+	->  match_score(Match, Score)
+	;   Score = 0
+	),
+
 	rdf_bnode(Confirm),
 	rdfh_transaction((rdfh_assert(Confirm, pprime:match, literal(Match)),
-			 rdfh_assert(Confirm, pprime:source, Source),
-			 rdfh_assert(Confirm, pprime:target, Target))),
-	match_score(Match, Score),
+			  rdfh_assert(Confirm, pprime:creator, User),
+			  rdfh_assert(Confirm, pprime:matchSource, Source),
+			  rdfh_assert(Confirm, pprime:matchTarget, Target))),
+
   	reply_json(json([source=Source,
 			 target=Target,
 			 match=Match,
 			 score=Score
  			])).
 
+
+confirmed(specific, Source, Target, User) :-
+	rdf(Confirm, pprime:match, literal(Match)),
+	\+ rdf(Confirm, pprime:creator, User),
+	(   Match = specific
+	->  confirmed_(Confirm, Source, Target)
+	;   Match = generic
+	->  confirmed_(Confirm, Target, Source)
+	).
+confirmed(generic, Source, Target, User) :-
+	rdf(Confirm, pprime:match, literal(Match)),
+	\+ rdf(Confirm, pprime:creator, User),
+	(   Match = generic
+	->  confirmed_(Confirm, Source, Target)
+	;   Match = specific
+	->  confirmed_(Confirm, Target, Source)
+	).
+confirmed(Match, Source, Target, User) :-
+	rdf(Confirm, pprime:match, literal(Match)),
+	\+ rdf(Confirm, pprime:creator, User),
+	(   confirmed_(Confirm, Source, Target)
+	;   confirmed_(Confirm, Target, Source)
+	).
+
+confirmed_(Confirm, Source, Target) :-
+	rdf(Confirm, pprime:matchSource, Source),
+	rdf(Confirm, pprime:matchTarget, Target).
+
 match_score(stem, 10).
 match_score(synonym, 15).
 match_score(specific, 20).
+match_score(generic, 20).
+
+
+%%	http_yaz_api_mgarden_data(+Request)
+%
+%	Handler for request of match data.
+
+http_yaz_api_mgarden_data(Request) :-
+	http_parameters(Request,
+			[ user(User,
+			       [description('URL of the user')])
+			]),
+	current_user_process(Process),
+	Obj = json([match=Match, score=Score]),
+	findall(Obj, user_confirmed(User, Process, Match, Score), Confirmed),
+  	reply_json(Confirmed).
 
+user_confirmed(User, Process, Confirm, Score) :-
+	rdf(Confirm, pprime:creator, User, Process),
+	rdf(Confirm, pprime:match, literal(Match)),
+	rdf(Confirm, pprime:matchSource, Source),
+	rdf(Confirm, pprime:matchTarget, Target),
+	(   confirmed(Match, Source, Target, User)
+	->  match_score(Match, Score)
+	;   Score = 0
+	).
diff --git a/applications/yaz_sgarden.pl b/applications/yaz_sgarden.pl
index 271a609..6c1d77b 100644
--- a/applications/yaz_sgarden.pl
+++ b/applications/yaz_sgarden.pl
@@ -33,25 +33,44 @@
 %	of it.
 
 http_yaz_sgarden(Request) :-
-	ensure_logged_on(_),
+	ensure_logged_on(User0),
+	user_property(User0, url(CurrentUser)),
 	http_parameters(Request,
 			[ video(Video,
 				[description('Current video')]),
 			  process(Process,
-			       [optional(true), desription('When set only annotations within this process are shown')]),
+			       [optional(true),
+				desription('When set only annotations within this process are shown')]),
 			  user(User,
-				[optional(true), description('When set only annotations created by this user are shown')])
+				[default(CurrentUser),
+				 description('When set only annotations created by this user are shown')])
  			]),
 	Options = [process(Process),
 		   user(User)
 		  ],
-	create_user_process([rdf:type=pprime:'sgarden',
-			     opmv:used=Video
-			    ], _Process),
-	video_annotations(Video, Annotations0, Options),
-	sort_by_arg(Annotations0, 2, Annotations),
+	create_user_process(CurrentUser, [rdf:type=pprime:'sgarden',
+				   opmv:used=Video
+				  ], _Process),
+	video_annotations(Video, As, Options),
+	tag_matches(As, As1),
+	sort_by_arg(As1, 2, Annotations),
  	html_video_page(Video, Annotations, 0, Options).
 
+tag_matches([], []).
+tag_matches([A0|As], [A|Rest]) :-
+	A0 = annotation(Value,Start,End,Entries),
+	A =  annotation(Value,Start,End,Entries,Match),
+	findall(S, (member(i(E,_),Entries),
+		    rdf(E, pprime:score, S)
+		   ),
+		Ss),
+	(   max_list(Ss, Score)
+	->  Match = match(exact, score(Score))
+	;   Match = @false
+	),
+ 	tag_matches(As,	Rest).
+
+
 
 %%	html_video_page(+Video, +Annotations, +StartTime, +Options)
 %
diff --git a/applications/yaz_tag_garden.pl b/applications/yaz_tag_garden.pl
index d4f7429..1b35c81 100644
--- a/applications/yaz_tag_garden.pl
+++ b/applications/yaz_tag_garden.pl
@@ -37,7 +37,8 @@
 :- http_handler(yaz('data/frames'), http_data_frames, []).
 
 http_yaz_tag_garden(Request) :-
-	ensure_logged_on(_),
+	ensure_logged_on(User0),
+	user_property(User0, url(CurrentUser)),
 	http_parameters(Request,
 			[ video(Video,
 				[description('Current video')]),
@@ -60,9 +61,9 @@ http_yaz_tag_garden(Request) :-
 		   interval(Interval),
 		   confirmed(Confirmed)
 		  ],
-	create_user_process([rdf:type=pprime:'TagGarden',
-			     opmv:used=Video
-			    ], _Process),
+	create_user_process(CurrentUser, [rdf:type=pprime:'TagGarden',
+					  opmv:used=Video
+					 ], _Process),
 	video_annotations(Video, Annotations, Options),
 	group_annotations(Annotations, AnnotationGroups),
  	html_garden_page(Video, AnnotationGroups, Options).
diff --git a/lib/user_process.pl b/lib/user_process.pl
index 5666dea..ebe6376 100644
--- a/lib/user_process.pl
+++ b/lib/user_process.pl
@@ -3,9 +3,9 @@
 	    user_process_creator/2,        % +ProcessURI, ?User
 	    user_process_joined/2,         % +ProcessURI, ?User
 	    set_active_process/1,          % +ProcessURI
-	    create_user_process/2,         % +Properties, -ProcessURI
+	    create_user_process/3,         % +User, +Properties, -ProcessURI
 	    start_user_process/1,          % ?ProcessURI
-	    join_user_process/1,           % +ProcessURI
+	    join_user_process/2,           % +ProcessURI
  	    end_user_process/1,	           % +ProcessURI
 	    add_resource_properties/2,	   % +URI, +Properties:list(p=v)
 	    resource_properties/2	   % +URI, ?Properties:list(p=v)
@@ -13,6 +13,7 @@
 
 :- use_module(library(http/http_session)).
 :- use_module(library(semweb/rdf_db)).
+:- use_module(library(semweb/rdfs)).
 :- use_module(user(user_db)).
 
 /** <module> Creation of processes in which annotations are made/modified
@@ -25,7 +26,7 @@ http://openprovenance.org/.
 */
 
 :- rdf_meta
-	create_user_process(t, r).
+	create_user_process(r, t, r).
 
 %%	current_user_process(-Process)
 %
@@ -64,19 +65,18 @@ set_active_process(Process) :-
 %	True if Process is the current process of User and has
 %	Properties. Creates a new user process if it doesn't exist.
 
-create_user_process(Properties, Process) :-
+create_user_process(_User, Properties, Process) :-
 	current_user_process(Process),
 	\+ rdf(Process, opmv:wasStartedAt, _),
 	resource_properties(Process, Properties),
 	!,
 	set_active_process(Process).
-create_user_process(Properties,	Process) :-
+create_user_process(User, Properties, Process) :-
 	(   var(Process)
 	->  rdf_bnode(Process)
 	;   true
 	),
-	current_user_url(User),
-	set_active_process(Process),
+ 	set_active_process(Process),
 	http_session_id(Session),
 	rdf_transaction((rdf_assert(Process, rdf:type, opmv:'Process', Process),
  			 rdf_assert(Process, opmv:wasControlledBy, User, Process),
@@ -85,20 +85,12 @@ create_user_process(Properties,	Process) :-
 			)),
 	debug(user_process, 'Process ~w created by ~w', [Process, User]).
 
-%%	start_user_process(?Process)
+%%	start_user_process(+Process)
 %
-%	Start a process by assert the start time. When Process is
-%	variable a new process is created.
+%	Start a process by assert the start time.
 
 start_user_process(Process) :-
-	var(Process),
-	!,
-	create_user_process([], Process),
-	start_user_process_(Process).
-start_user_process(Process) :-
-	start_user_process_(Process).
-
-start_user_process_(Process) :-
+	rdfs_individual_of(Process, opmv:'Process'),
 	get_time(StartTime0),
 	format_iso_dateTime(StartTime0, StartTime),
 	rdf_transaction(rdf_assert(Process, opmv:wasStartedAt, literal(type(xsd:date, StartTime)), Process)),
@@ -109,18 +101,19 @@ start_user_process_(Process) :-
 %	End a process, by asserting the endTime
 
 end_user_process(Process) :-
+	rdfs_individual_of(Process, opmv:'Process'),
  	get_time(EndTime0),
 	format_iso_dateTime(EndTime0, EndTime),
 	rdf_transaction((rdf_assert(Process, opmv:wasEndedAt, literal(type(xsd:date, EndTime), Process), Process)
   			)),
 	debug(user_process, 'Process ~w ended at ~w', [Process, EndTime]).
 
-%%	join_user_process(+Process)
+%%	join_user_process(+Process, +User)
 %
 %	Add current user agent to a Process.
 
-join_user_process(Process) :-
-	current_user_url(User),
+join_user_process(Process, User) :-
+	rdfs_individual_of(Process, opmv:'Process'),
 	set_active_process(Process),
   	rdf_transaction(rdf_assert(Process, opmv:wasPerformedBy, User, Process)),
 	debug(user_process, 'Process ~w joined by ~w', [Process, User]).
diff --git a/lib/yaz_util.pl b/lib/yaz_util.pl
index 0fba75a..ad5f994 100644
--- a/lib/yaz_util.pl
+++ b/lib/yaz_util.pl
@@ -335,7 +335,8 @@ http:convert_parameter(jsonresource, Atom, Term) :-
     annotation(tag:_, tags:list, count:number),
     annotation(tag:_, startTime:number, endTime:number, annotations:list),
     annotation(tag:_, startTime:number, endTime:number, annotations:list, match:_),
-    match(type:atom, uri:_, value:_).
+    match(type:atom, score:_),
+    match(type:atom, score:_, uri:_, value:_).