virtualcommons-svn Mailing List for Virtual Commons Experiment Software (Page 12)
Status: Beta
Brought to you by:
alllee
You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
(21) |
Aug
(31) |
Sep
(6) |
Oct
(15) |
Nov
(2) |
Dec
(9) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
(4) |
Feb
(6) |
Mar
(12) |
Apr
(52) |
May
(14) |
Jun
(19) |
Jul
(81) |
Aug
(115) |
Sep
(36) |
Oct
(88) |
Nov
(46) |
Dec
(58) |
2010 |
Jan
(52) |
Feb
(55) |
Mar
(48) |
Apr
(15) |
May
(5) |
Jun
(38) |
Jul
(27) |
Aug
(24) |
Sep
(28) |
Oct
(1) |
Nov
(2) |
Dec
(29) |
2011 |
Jan
(87) |
Feb
(39) |
Mar
(63) |
Apr
(42) |
May
(26) |
Jun
(53) |
Jul
(23) |
Aug
(43) |
Sep
(37) |
Oct
(25) |
Nov
(4) |
Dec
(7) |
2012 |
Jan
(73) |
Feb
(79) |
Mar
(62) |
Apr
(28) |
May
(12) |
Jun
(2) |
Jul
(9) |
Aug
(1) |
Sep
(8) |
Oct
|
Nov
(3) |
Dec
(3) |
2013 |
Jan
(8) |
Feb
(16) |
Mar
(38) |
Apr
(74) |
May
(62) |
Jun
(15) |
Jul
(49) |
Aug
(19) |
Sep
(9) |
Oct
|
Nov
|
Dec
|
2014 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(25) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: A L. <iss...@bi...> - 2013-03-28 15:47:46
|
New issue 97: boundaries: change harvest decision allocation https://bitbucket.org/virtualcommons/vcweb/issue/97/boundaries-change-harvest-decision A Lee: Change harvest decision algorithm: When total group harvest > resource level: Allocate all trees to each participant in round that requested any (until they reach their specified harvest decision or trees run out). for tree in remaining trees: Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: <com...@bi...> - 2013-03-28 15:27:53
|
3 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/8f843c60b99b/ Changeset: 8f843c60b99b User: alllee Date: 2013-03-28 15:50:47 Summary: adding an all_participants_ready parameter to the participant-ready POST endpoint response informing the client whether or not all participants are ready. Should add Experimenter polling of the check-ready-participants endpoint next. adding a username suffix when setting up test participants via email so we can use mailinator.com more effectively Affected #: 4 files diff -r ffea45351c4a656e496838477453648ed82a8793 -r 8f843c60b99b0837b1b07f090d68a3253d72b5b5 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -444,8 +444,11 @@ $.post('/experiment/participant-ready', { participant_group_id: model.participantGroupId() }, function(response) { console.debug("successfully posted to server, notifying sockjs"); console.debug(response); + model.readyParticipants(response.number_of_ready_participants); getWebSocket().send(createMessageEvent("Participant finished reading instructions", "client_ready")); - model.readyParticipants(response.number_of_ready_participants); + if (response.all_participants_ready) { + getWebSocket().send(createAllParticipantsReadyEvent()); + } model.activateTemplate("WAITING_ROOM"); }); } @@ -504,6 +507,8 @@ console.debug(formData); $.post('submit-harvest-decision', formData, function(response) { console.log(response); + // FIXME: this is dangerous, could potentially lead to advancing rounds multiple times if something + // haywire in the participant. Should only be activatable by the Experimenter. console.log("all participants ready?"); if (response.all_participants_submitted) { getWebSocket().send(createAllParticipantsReadyEvent()); @@ -585,9 +590,7 @@ break; case 'participant_ready': $.get('/experiment/{{experiment.pk}}/ready-participants', function(response) { - console.debug("ready participants response"); - console.debug(response) - experimentModel.readyParticipants(response.number_of_ready_participants); + experimentModel.readyParticipants(response.number_of_ready_participants); }); break; default: diff -r ffea45351c4a656e496838477453648ed82a8793 -r 8f843c60b99b0837b1b07f090d68a3253d72b5b5 vcweb/core/forms.py --- a/vcweb/core/forms.py +++ b/vcweb/core/forms.py @@ -123,8 +123,16 @@ class RegisterSimpleParticipantsForm(RegisterParticipantsForm): - email_suffix = forms.CharField(min_length=3, initial='asu.edu', - help_text=_('An email suffix without the "@" symbol. Generated participants will have usernames of the format s1..sn@email_suffix. For example, if you register 20 participants with an email suffix of example.edu, the system will generate 20 participants with usernames ranging from s1...@ex..., s2...@ex..., s3...@ex..., ... s2...@ex....')) + username_suffix = forms.CharField(min_length=3, initial='asu', + help_text=_('''Appended to every generated username before the "@" symbol, e.g., s1...@fo...''')) + email_suffix = forms.CharField(min_length=3, initial='mailinator.com', + help_text=_(''' + An email suffix without the "@" symbol. Generated participants will have usernames of the format + s1<username_suffix>@<email_suffix>..sn<username_suffix>@<email_suffix>. For example, if you register 20 + participants with a username suffix of asu and an email suffix of mailinator.com, the system will generate + 20 participants with usernames ranging from s1...@ma..., s2...@ma..., + s3...@ma..., ... s2...@ma.... + ''')) number_of_participants = forms.IntegerField(min_value=1, help_text=_('The number of participants to register with this experiment.')) class RegisterEmailListParticipantsForm(RegisterParticipantsForm): diff -r ffea45351c4a656e496838477453648ed82a8793 -r 8f843c60b99b0837b1b07f090d68a3253d72b5b5 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -383,6 +383,10 @@ self.sequence_label) @property + def number_of_participants(self): + return self.participant_set.count() + + @property def participant_group_relationships(self): ''' Generator function for all participant group relationships in this experiment @@ -650,13 +654,13 @@ return msg ''' FIXME: get rid of hardcoded defaults for the slovakia pretest ''' - def setup_test_participants(self, count=20, institution=None, email_suffix='sav.sk', password='test'): + def setup_test_participants(self, count=20, institution=None, email_suffix='mailinator.com', username_suffix='asu', password='test'): if self.participant_set.count() > 0: logger.warning("This experiment %s already has %d participants - aborting", self, self.participant_set.count()) return users = [] for i in xrange(1, count+1): - email = u's%d@%s' % (i, email_suffix) + email = u's%d%s@%s' % (i, username_suffix, email_suffix) try: user = User.objects.get(username=email) except User.DoesNotExist: diff -r ffea45351c4a656e496838477453648ed82a8793 -r 8f843c60b99b0837b1b07f090d68a3253d72b5b5 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -320,12 +320,14 @@ def form_valid(self, form): number_of_participants = form.cleaned_data.get('number_of_participants') + username_suffix = form.cleaned_data.get('username_suffix') email_suffix = form.cleaned_data.get('email_suffix') experiment = self.object experiment_passcode = form.cleaned_data.get('experiment_passcode') experiment.setup_test_participants(count=number_of_participants, institution=form.institution, email_suffix=email_suffix, + username_suffix=username_suffix, password=experiment_passcode) return super(RegisterSimpleParticipantsView, self).form_valid(form) @@ -552,8 +554,15 @@ prdv.submitted = True prdv.boolean_value = True prdv.save() - return JsonResponse(dumps({'success': True, 'number_of_ready_participants': experiment.number_of_ready_participants})) - return JsonResponse(dumps({'success': False})) + number_of_ready_participants = experiment.number_of_ready_participants + all_participants_ready = (number_of_ready_participants == experiment.number_of_participants) + return JsonResponse(dumps({ + 'success': True, + 'number_of_ready_participants': number_of_ready_participants, + 'all_participants_ready': all_participants_ready + })) + else: + return JsonResponse(dumps({'success': False, 'message': "Invalid form"})) @participant_required def get_number_of_ready_participants(request, pk=None): https://bitbucket.org/virtualcommons/vcweb/commits/4f735c36bd53/ Changeset: 4f735c36bd53 User: alllee Date: 2013-03-28 16:09:57 Summary: changing control flow: Previously, the last participant would receive a response with "all participants are ready" at which point it would notify the realtime server which notifies the experimenter which notifies the django server to move to the next round Now, participants just signal that they are ready to the django server and realtime server. Every time the experimenter receives a realtime participant_ready event it polls the check-ready-participants endpoint to see if all the participants are ready and if so, advances to the next round. The ideal situation would still be for the django server to advance the round directly and then tell the sockjs server to update all connected clients. TODO: wire up boundaries submit decision endpoint to set up participant_ready properly Affected #: 4 files diff -r 8f843c60b99b0837b1b07f090d68a3253d72b5b5 -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -446,9 +446,11 @@ console.debug(response); model.readyParticipants(response.number_of_ready_participants); getWebSocket().send(createMessageEvent("Participant finished reading instructions", "client_ready")); + /* if (response.all_participants_ready) { getWebSocket().send(createAllParticipantsReadyEvent()); } + */ model.activateTemplate("WAITING_ROOM"); }); } @@ -509,10 +511,12 @@ console.log(response); // FIXME: this is dangerous, could potentially lead to advancing rounds multiple times if something // haywire in the participant. Should only be activatable by the Experimenter. + /* console.log("all participants ready?"); if (response.all_participants_submitted) { getWebSocket().send(createAllParticipantsReadyEvent()); } + */ model.update($.parseJSON(response.experimentModelJson)); // FIXME: forward the response message to the chat window should be handled completely on the server // side instead of ping-ponging to the client side back to the real time server back out to all @@ -589,7 +593,7 @@ experimentModel.update(); break; case 'participant_ready': - $.get('/experiment/{{experiment.pk}}/ready-participants', function(response) { + $.get('/experiment/{{experiment.pk}}/check-ready-participants', function(response) { experimentModel.readyParticipants(response.number_of_ready_participants); }); break; diff -r 8f843c60b99b0837b1b07f090d68a3253d72b5b5 -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -260,7 +260,7 @@ model.setCurrentInterval( setInterval( model.tick, 1000 ) ); } }; - model.nextRound = function() { + model.advanceToNextRound = function() { $('#progress-modal').modal('show'); Dajaxice.vcweb.core.experiment_controller(function(data) { ko.mapping.fromJS(data, model); @@ -294,6 +294,14 @@ model.startOrStopExperimentActionText = ko.computed(function() { return model.isRoundInProgress() ? "stop" : "start"; }); + model.checkAllParticipantsReady = function() { + $.get('/experiment/{{experiment.pk}}/check-ready-participants', function(response) { + if (response.all_participants_ready) { + model.addMessage("All participants are ready, advancing to next round"); + model.advanceToNextRound(); + } + }); + } model.updateParticipants = function(m, evt) { confirmAction(evt.target, function(confirmed, action) { if (confirmed) { @@ -336,8 +344,8 @@ case 'update': console.debug("FIXME: ignoring update requests, patch sockjs broadcast to not send certain messages"); break; - case 'all_participants_ready': - experimentModel.nextRound(); + case 'participant_ready': + experimentModel.checkAllParticipantsReady(); case 'chat': case 'info': default: diff -r 8f843c60b99b0837b1b07f090d68a3253d72b5b5 -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 vcweb/core/urls.py --- a/vcweb/core/urls.py +++ b/vcweb/core/urls.py @@ -21,7 +21,7 @@ url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), url(r'^experiment/add$', add_experiment, name='add_experiment'), url(r'^experiment/participant-ready$', participant_ready, name='participant_ready'), - url(r'^experiment/(?P<pk>\d+)/ready-participants$', get_number_of_ready_participants, name='number_of_ready_participants'), + url(r'^experiment/(?P<pk>\d+)/check-ready-participants$', get_number_of_ready_participants, name='number_of_ready_participants'), url(r'^experiment/(?P<pk>\d+)/monitor$', monitor, name='monitor_experiment'), url(r'^experiment/(?P<pk>\d+)/register-email-list$', RegisterEmailListView.as_view(), name='register_email_list'), url(r'^experiment/(?P<pk>\d+)/register-simple$', RegisterSimpleParticipantsView.as_view(), name='register_simple'), diff -r 8f843c60b99b0837b1b07f090d68a3253d72b5b5 -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -554,20 +554,19 @@ prdv.submitted = True prdv.boolean_value = True prdv.save() - number_of_ready_participants = experiment.number_of_ready_participants - all_participants_ready = (number_of_ready_participants == experiment.number_of_participants) - return JsonResponse(dumps({ - 'success': True, - 'number_of_ready_participants': number_of_ready_participants, - 'all_participants_ready': all_participants_ready - })) + return JsonResponse(dumps(_ready_participants_dict(experiment))) else: return JsonResponse(dumps({'success': False, 'message': "Invalid form"})) -@participant_required +def _ready_participants_dict(experiment): + number_of_ready_participants = experiment.number_of_ready_participants + all_participants_ready = (number_of_ready_participants == experiment.number_of_participants) + return { 'success': True, 'number_of_ready_participants': number_of_ready_participants, 'all_participants_ready': all_participants_ready } + +@login_required def get_number_of_ready_participants(request, pk=None): experiment = get_object_or_404(Experiment, pk=pk) - return JsonResponse(dumps({'success': True, 'number_of_ready_participants': experiment.number_of_ready_participants})) + return JsonResponse(dumps(_ready_participants_dict(experiment))) def handler500(request): return render(request, '500.html') https://bitbucket.org/virtualcommons/vcweb/commits/2391be49b5fa/ Changeset: 2391be49b5fa User: alllee Date: 2013-03-28 16:27:32 Summary: s/client_ready/participant_ready for consistency adding convenience method to ParticipantGroupRelationship to signify that the participant is ready setting up auto-transition for round checkpoint when submitting decisions Affected #: 7 files diff -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 -r 2391be49b5fa81d27a4666f10fb80ed24ec8bee8 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -445,12 +445,7 @@ console.debug("successfully posted to server, notifying sockjs"); console.debug(response); model.readyParticipants(response.number_of_ready_participants); - getWebSocket().send(createMessageEvent("Participant finished reading instructions", "client_ready")); - /* - if (response.all_participants_ready) { - getWebSocket().send(createAllParticipantsReadyEvent()); - } - */ + getWebSocket().send(createReadyEvent("Participant finished reading instructions")); model.activateTemplate("WAITING_ROOM"); }); } @@ -509,19 +504,11 @@ console.debug(formData); $.post('submit-harvest-decision', formData, function(response) { console.log(response); - // FIXME: this is dangerous, could potentially lead to advancing rounds multiple times if something - // haywire in the participant. Should only be activatable by the Experimenter. - /* - console.log("all participants ready?"); - if (response.all_participants_submitted) { - getWebSocket().send(createAllParticipantsReadyEvent()); - } - */ model.update($.parseJSON(response.experimentModelJson)); // FIXME: forward the response message to the chat window should be handled completely on the server // side instead of ping-ponging to the client side back to the real time server back out to all // clients in this group - getWebSocket().send(createMessageEvent(response.message)); + getWebSocket().send(createReadyEvent(response.message)); model.clearCurrentInterval(); }); } diff -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 -r 2391be49b5fa81d27a4666f10fb80ed24ec8bee8 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -38,13 +38,13 @@ harvest_decision = form.cleaned_data['integer_decision'] round_data = experiment.current_round_data set_harvest_decision(pgr, harvest_decision, round_data, submitted=True) + pgr.set_participant_ready(round_data) message = "%s harvested %s trees" experiment.log(message % (pgr.participant, harvest_decision)) response_dict = { 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr), 'message': message % (pgr.participant_handle, harvest_decision), - 'all_participants_submitted': experiment.all_participants_submitted(get_harvest_decision_parameter(), round_data) } return JsonResponse(dumps(response_dict)) else: diff -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 -r 2391be49b5fa81d27a4666f10fb80ed24ec8bee8 vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -618,7 +618,7 @@ } model.participantReady = function () { $.post('/experiment/participant-ready', { participant_group_id: model.participantGroupId() }, function (response) { - getWebSocket().send(createMessageEvent("Participant finished reading instructions", "client_ready")); + getWebSocket().send(createReadyEvent("Participant finished reading instructions")); model.readyParticipants(response.number_of_ready_participants); model.activateWaitingRoomPage(); }); diff -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 -r 2391be49b5fa81d27a4666f10fb80ed24ec8bee8 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1875,6 +1875,15 @@ def group_number(self): return self.group.number + def set_participant_ready(self, round_data=None): + if round_data is None: + round_data = self.current_round_data + dv = self.get_data_value(parameter=get_participant_ready_parameter(), round_data=round_data) + dv.submitted = True + dv.boolean_value = True + dv.save() + return dv + def get_round_configuration_value(self, **kwargs): return self.group.get_round_configuration_value(**kwargs) diff -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 -r 2391be49b5fa81d27a4666f10fb80ed24ec8bee8 vcweb/core/templates/includes/participant.events.html --- a/vcweb/core/templates/includes/participant.events.html +++ b/vcweb/core/templates/includes/participant.events.html @@ -5,8 +5,8 @@ function createReconnectionEvent() { return createMessageEvent("Reconnecting from disconnect", "reconnect"); } -function createAllParticipantsReadyEvent() { - return createMessageEvent("All participants ready", "all_participants_ready"); +function createReadyEvent(message) { + return createMessageEvent(message, "participant_ready"); } function createMessageEvent(payload, event_type) { if (! event_type) { diff -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 -r 2391be49b5fa81d27a4666f10fb80ed24ec8bee8 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -549,11 +549,7 @@ pk=participant_group_id) experiment = pgr.group.experiment round_data = experiment.current_round_data - prdv = ParticipantRoundDataValue.objects.get(participant_group_relationship=pgr, - round_data=round_data, parameter=get_participant_ready_parameter()) - prdv.submitted = True - prdv.boolean_value = True - prdv.save() + pgr.set_participant_ready(round_data) return JsonResponse(dumps(_ready_participants_dict(experiment))) else: return JsonResponse(dumps({'success': False, 'message': "Invalid form"})) diff -r 4f735c36bd53022621b5b7f62585a5c75fe2a4f6 -r 2391be49b5fa81d27a4666f10fb80ed24ec8bee8 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -70,6 +70,10 @@ def create_message_event(message, event_type='info'): return json.dumps({ 'message': message, 'event_type': event_type}) +REFRESH_EVENT_TYPE = 'refresh' +UPDATE_EVENT_TYPE = 'update' +READY_EVENT_TYPE = 'participant_ready' + REFRESH_EVENT = json.dumps({ 'event_type': 'refresh' }) UPDATE_EVENT = json.dumps({ 'event_type': 'update' }) DISCONNECTION_EVENT = create_message_event('Your session has expired and you have been disconnected. You can only have one window open to a vcweb page.') @@ -290,11 +294,11 @@ logger.warning("Invalid auth token for participant %s", per) self.send(UNAUTHORIZED_EVENT) - def handle_client_ready(self, event, experiment, **kwargs): - logger.debug("handling client ready event %s for experiment %s", event, experiment) + def handle_participant_ready(self, event, experiment, **kwargs): + logger.debug("handling participant ready event %s for experiment %s", event, experiment) (per, valid) = self.verify_auth_token(event) if valid: - connection_manager.broadcast(experiment, create_message_event("Participant %s is ready." % per.participant, event_type='participant_ready')) + connection_manager.broadcast(experiment, create_message_event("Participant %s is ready." % per.participant, event_type=READY_EVENT_TYPE)) else: logger.warning("Invalid auth token for participant %s", per) self.send(UNAUTHORIZED_EVENT) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-28 07:50:39
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/ffea45351c4a/ Changeset: ffea45351c4a User: alllee Date: 2013-03-28 08:50:23 Summary: fixing chat form disabling logic once again, really need to clean up the flow control here Affected #: 1 file diff -r 0852d8738d3caeeae27fad584a385956ac606873 -r ffea45351c4a656e496838477453648ed82a8793 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -555,12 +555,14 @@ model.setFormDisabled("#chat-form", true); } model.setupChat = function() { - model.setFormDisabled("#chat-form", ! model.chatEnabled()); + var chatDisabled = model.isPracticeRound() || ! model.chatEnabled(); + model.setFormDisabled("#chat-form", chatDisabled); } model.afterRenderTemplate = function(elements) { if (model.templateId() === "REGULAR") { model.startRound() } + model.setupChat(); } return model; } Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-28 07:43:53
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/0852d8738d3c/ Changeset: 0852d8738d3c User: alllee Date: 2013-03-28 08:43:38 Summary: patching sockjs server to be session id aware when multiple vcweb groups exist adding proper other group average harvest / storage and resource levels to view model when canObserveOtherGroup is enabled. Affected #: 4 files diff -r 653919ea2f1121bb268f384e9528882014fc3205 -r 0852d8738d3caeeae27fad584a385956ac606873 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -100,6 +100,12 @@ ''' group data accessors ''' +def get_average_harvest(group, round_data): + return get_total_harvest(group, round_data) / float(group.size) + +def get_average_storage(group, round_data): + return get_total_storage(group, round_data) / float(group.size) + def get_resource_level_dv(group, round_data=None, round_configuration=None): ''' Returns either the GroupClusterDataValue (shared resource condition) or the GroupRoundDataValue (standard @@ -137,11 +143,9 @@ return get_storage_dv(participant_group_relationship, round_data, default).int_value # returns the sum of all stored resources for each member in the group -def get_total_storage(group): - # FIXME: int_value would be more performant but storage isn't being initialized properly yet and value returns an - # appropriate default value - return sum([pdv.value for pdv in group.get_participant_data_values(parameter=get_storage_parameter())]) - +def get_total_storage(group, round_data): + q = ParticipantRoundDataValue.objects.for_group(group=group, parameter=get_storage_parameter(), round_data=round_data).aggregate(total_storage=Sum('int_value')) + return q['total_storage'] def set_storage(participant_group_relationship, round_data, value): storage_dv = get_storage_dv(participant_group_relationship, round_data) diff -r 653919ea2f1121bb268f384e9528882014fc3205 -r 0852d8738d3caeeae27fad584a385956ac606873 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -8,7 +8,7 @@ from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_max_allowed_harvest_decision, get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, get_last_harvest_decision, get_harvest_decision_dv, get_harvest_decision_parameter, set_harvest_decision, - can_observe_other_group, get_player_status) + can_observe_other_group, get_player_status, get_average_harvest, get_average_storage) import logging logger = logging.getLogger(__name__) @@ -71,6 +71,7 @@ 'harvestDecision': 0, 'roundDuration': 60, 'chatMessages': [], + 'canObserveOtherGroup': False, 'isInstructionsRound': False, } # FIXME: need to distinguish between instructions / welcome rounds and practice/regular rounds @@ -135,19 +136,11 @@ 'message': cm.string_value, 'date_created': cm.date_created.strftime("%I:%M:%S") } for cm in ChatMessage.objects.for_group(own_group)] - experiment_model_dict['canObserveOtherGroup'] = can_observe_other_group(current_round) - if not current_round.is_practice_round and experiment_model_dict['canObserveOtherGroup']: - gr = GroupRelationship.objects.select_related('cluster').get(group=own_group) - group_data = [] - for group in gr.cluster.group_set.all(): - if group != own_group: - group_data.append({ - 'groupId': unicode(group), - 'resourceLevel': get_resource_level(group), - 'totalStorage': get_total_storage(group), - 'regrowthRate': regrowth_rate, - 'costOfLiving': cost_of_living, - }) - experiment_model_dict['groupData'] = group_data + if can_observe_other_group(current_round): + experiment_model_dict['canObserveOtherGroup'] = True + other_group = own_group.get_related_group() + experiment_model_dict['otherGroupResourceLevel'] = get_resource_level(other_group, current_round_data) + experiment_model_dict['otherGroupAverageHarvest'] = get_average_harvest(other_group, current_round_data) + experiment_model_dict['otherGroupAverageStorage'] = get_average_storage(other_group, current_round_data) return dumps(experiment_model_dict) diff -r 653919ea2f1121bb268f384e9528882014fc3205 -r 0852d8738d3caeeae27fad584a385956ac606873 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -557,13 +557,15 @@ def get_participant_experiment_relationship(self, participant): return self.participant_relationship_set.select_related('participant__user').get(participant=participant) - def get_participant_group_relationship(self, participant): + def get_participant_group_relationship(self, participant=None, participant_pk=None): session_id = self.current_round.session_id + criteria = dict([ + ('group__experiment', self), + ('participant__pk', participant_pk) if participant_pk else ('participant', participant), + ]) if session_id: - return ParticipantGroupRelationship.objects.get(group__experiment=self, participant=participant, - group__session_id=session_id) - else: - return ParticipantGroupRelationship.objects.get(group__experiment=self, participant=participant) + criteria['group__session_id'] = session_id + return ParticipantGroupRelationship.objects.get(**criteria) def all_participants_have_submitted(self): return ParticipantRoundDataValue.objects.filter(submitted=False, round_data=self.current_round_data).count() == 0 @@ -1454,9 +1456,9 @@ return self.activity_log_set.filter(round_configuration=self.current_round) def get_related_group(self): - ''' FIXME: currently only assumes single relationships ''' + ''' FIXME: currently only assumes single paired relationships ''' gr = GroupRelationship.objects.get(group=self) - related_gr = GroupRelationship.objects.get(~models.Q(group=self), cluster=gr.cluster) + related_gr = GroupRelationship.objects.select_related('group').get(~models.Q(group=self), cluster=gr.cluster) return related_gr.group def log(self, log_message): diff -r 653919ea2f1121bb268f384e9528882014fc3205 -r 0852d8738d3caeeae27fad584a385956ac606873 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -129,10 +129,10 @@ if experimenter_tuple in self.experimenter_to_connection: del self.experimenter_to_connection[experimenter_tuple] - def get_participant_group_relationship(self, connection): + def get_participant_group_relationship(self, connection, experiment): (participant_pk, experiment_pk) = self.connection_to_participant[connection] logger.debug("Looking for ParticipantGroupRelationship with tuple (%s, %s)", participant_pk, experiment_pk) - return ParticipantGroupRelationship.objects.get(participant__pk=participant_pk, group__experiment__pk = experiment_pk) + return experiment.get_participant_group_relationship(participant_pk) def get_participant_experiment_tuple(self, connection): return self.connection_to_participant[connection] @@ -314,7 +314,7 @@ def handle_chat(self, event, experiment, **kwargs): (per, valid) = self.verify_auth_token(event) if valid: - pgr = connection_manager.get_participant_group_relationship(self) + pgr = connection_manager.get_participant_group_relationship(self, experiment) current_round_data = experiment.current_round_data # FIXME: should chat message be created via post to Django form instead? chat_message = ChatMessage.objects.create(participant_group_relationship=pgr, Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-28 07:18:24
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/653919ea2f11/ Changeset: 653919ea2f11 User: alllee Date: 2013-03-28 08:18:08 Summary: group clustering cleanup Affected #: 1 file diff -r ae8d446dae622ca73a4fc54a3fbcce6dc16d16f7 -r 653919ea2f1121bb268f384e9528882014fc3205 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -747,7 +747,7 @@ gs = self.group_set if gs.count() > 0: if preserve_existing_groups: - self.log("preserving existing groups") + logger.debug("preserving existing groups") # verify incoming session id is an actual value if session_id is None: round_configuration = self.current_round @@ -756,25 +756,26 @@ logger.error("Trying to create a new set of groups but no session id has been set on %s. Aborting.", round_configuration) raise ValueError("Cannot allocate new groups and preserve existing groups without an appropriate session id set on this round configuration %s" % round_configuration) else: - self.log("reallocating groups, deleting old groups") + logger.debug("deleting old groups") gqs = gs.all() for g in gqs: self.log("reallocating/deleting group %s" % g.participant_group_relationship_set.all()) gqs.delete() - self.group_cluster_set.delete() - self.log("deleted all groups: %s" % str(gqs)) - else: - logger.debug("no existing groups, proceeding") - # seed the initial group. +# add each participant to the next available group + current_group = None for p in participants: - pgr = self.add_participant(p, max_group_size=max_group_size) + pgr = self.add_participant(p, current_group, max_group_size) current_group = pgr.group self.create_group_clusters() def create_group_clusters(self): round_configuration = self.current_round session_id = round_configuration.session_id + logger.debug("creating group clusters with session id %s", session_id) if round_configuration.create_group_clusters: + # NOTE: misconfiguration can cause data loss + # delete any group clusters with the same session id + self.group_cluster_set.filter(session_id=session_id).delete() group_cluster_size = round_configuration.group_cluster_size groups = list(self.group_set.filter(session_id=session_id)) if len(groups) % group_cluster_size != 0: @@ -1665,7 +1666,7 @@ gcdv.save() def __unicode__(self): - return u"group cluster %s (%s)" % (self.name, self.experiment) + return u"GroupCluster #%s %s (%s)" % (self.pk, self.session_id, self.experiment) class Meta: ordering = ['date_created'] @@ -1676,7 +1677,7 @@ group = models.ForeignKey(Group) def __unicode__(self): - return u"group %s in cluster %s" % (self.group, self.cluster) + return u"%s -> %s" % (self.group, self.cluster) class Meta: ordering = ['date_created'] Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-28 06:59:42
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/ae8d446dae62/ Changeset: ae8d446dae62 User: alllee Date: 2013-03-28 07:59:26 Summary: setting up treatment a instructions Affected #: 6 files diff -r 39c0b2f6304b71699416df6cb1c9928e458dd21f -r ae8d446dae622ca73a4fc54a3fbcce6dc16d16f7 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -162,7 +162,6 @@ status_dv.save() return status_dv - def get_last_harvest_decision(participant_group_relationship, round_data=None): return participant_group_relationship.get_data_value(parameter=get_harvest_decision_parameter(), round_data=round_data, default=0).int_value diff -r 39c0b2f6304b71699416df6cb1c9928e458dd21f -r ae8d446dae622ca73a4fc54a3fbcce6dc16d16f7 vcweb/boundaries/templates/boundaries/instructions-treatment-a.html --- a/vcweb/boundaries/templates/boundaries/instructions-treatment-a.html +++ /dev/null @@ -1,47 +0,0 @@ -{% if session_number == 1 %} -<h2>Paid Experiment Instructions</h2> -<h3>Two Sessions</h3> -<p> -This experiment is composed of two different, unconnected sessions. Your group will be randomly selected for each -session, so you will be playing with a different group each time. We will pay you for one of these two sessions, chosen -at random. You have exactly 50% chance of being paid for your earnings in either session. -</p> -<h3>Group and Individual Status</h3> -<p> -You will be able to observe the status of the members of your group each round. Likewise your group members can see -your status and those of the group. -</p> -<h3>Group Chat</h3> -<p> -You will be able to chat with the other members of your group via group text chat. Once you have made a harvest -decision, you will no longer be able to chat for that round. -</p> -<h3>Harvest Choice</h3> -<p> -You will have a maximum of <i class='icon-clock'></i><span data-bind='text: roundDuration'></span> seconds to make a -harvest decision each round. A countdown will alert you when there are -<span data-bind='text: warningCountdownTime'></span> seconds remaining to make a harvest choice. When the countdown -reaches zero, any value you have selected will be submitted. <strong>The default harvest is zero.</strong> -</p> -{% comment %} -FIXME: figure out how to pager between paid experiment instructions and the subsequent section (welcome to -session X), is tricky because of the transitions between rounds and the fact that session 2 doesn't need this same -pager, just the below instructions. -{% endcomment %} -{% endif %} -<h3>Welcome to Session {{ session_number }}</h3> -<p> -In this session, there are two groups or villages. Each group has a forest that the other group cannot harvest. Both -forests have the same growth capacity. In addition, you may observe the other group, their storage amounts, and their -forest status. Similarly, they may observe your group in the same way. -</p> -<p> -Key points: -</p> -<ul> - <li>Two groups</li> - <li>Each group has an exclusive forest of the same size</li> - <li>You may observe the other group</li> - <li>They may observe your group</li> -</ul> - diff -r 39c0b2f6304b71699416df6cb1c9928e458dd21f -r ae8d446dae622ca73a4fc54a3fbcce6dc16d16f7 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -1,5 +1,4 @@ {% extends "participant/base.html" %} -{% load tags %} {% load static %} {% block head %} {{ block.super }} @@ -19,12 +18,11 @@ </div></div> {% endblock content %} - {% block sidebar %} -<div data-bind='ifnot: instructionsRound'> +<div data-bind='ifnot: isInstructionsRound'><h3>Chat</h3><div data-bind='ifnot: chatEnabled'> - <div class='alert alert-info'> + <div class='alert alert-error'><i class='icon-warning-sign'></i> Chat is currently disabled. </div></div> @@ -53,17 +51,73 @@ <script type='text/html' id='PRACTICE_ROUND_RESULTS'><h3>Practice Round Results</h3><p> - If this had been been a paid session, you would have earned <span class='text-gold' data-bind='text: formatCurrency(totalEarnings)'></span>. + You harvested <span class='badge badge-success' data-bind='text: storage'></span> trees. + If this had been been a paid session, you would have earned <strong class='text-success' data-bind='text: totalEarnings'></strong>. </p><p> We will now move on to the <strong>paid rounds.</strong></p><ul class='pager'><li class='next'> - <a data-bind='click: activateTemplate.bind($data, "PAID_EXPERIMENT_INSTRUCTIONS")'>Ok, continue</a> + <a href='javascript: void()' data-bind='click: activateTemplate.bind($data, "PAID_EXPERIMENT_INSTRUCTIONS")'>Ok, continue</a></li></ul></script> +<script type='text/html' id='PAID_EXPERIMENT_INSTRUCTIONS'> + <h2>Paid Experiment Instructions</h2> + <h3>Two Sessions</h3> + <p> + This experiment is composed of two different, unconnected sessions. Your group will be randomly selected for each + session, so you will be playing with a different group each time. We will pay you for one of these two sessions, + chosen at random. You have exactly 50% chance of being paid for your earnings in each session. + </p> + <h3>Group and Individual Status</h3> + <p> + You will be able to observe the status of the members of your group each round. Likewise group members will see + your status, and those of the group. + </p> + <h3>Group Chat</h3> + <p> + You will be able to text chat with the other members of your group. Once you have made a harvest decision, you will + no longer be able to contribute to the chat for that round. + </p> + <h3>Harvest Choice</h3> + <p> + You will have a maximum of <i class='icon-clock'></i><span data-bind='text: roundDuration'></span> seconds to make a + harvest decision each round. A countdown will alert you when there are + <span data-bind='text: warningCountdownTime'></span> seconds remaining to make a harvest choice. When the countdown + reaches zero, any value you have selected will be submitted. <strong>The default harvest is zero.</strong> + </p> + + <ul class='pager'> + <li class='previous'> + <a href='javascript: void()' data-bind='click: activateTemplate.bind($data, "PRACTICE_ROUND_RESULTS")'>Back</a> + </li> + <li class='next'> + <a href='javascript: void()' data-bind='click: participantReady'>Ok, I understand</a> + </li> + </ul> +</script> +<script type='text/html' id='TREATMENT_A_INSTRUCTIONS'> +<h3>Session <span data-bind='text: sessionId'></span> Instructions</h3> +<p> +In this session, there are two groups or villages. Each group has a forest that the other group cannot harvest. Both +forests have the same growth capacity. In addition, you may observe the other group, their storage amounts, and their +forest status. Similarly, they may observe your group in the same way. +</p> +<h3>Key points</h3> +<ul> + <li>Two groups</li> + <li>Each group has an <b>exclusive</b> forest of the same size</li> + <li>You may observe the other group</li> + <li>They may observe your group</li> +</ul> +<ul class='pager'> + <li class='next'> + <a href='javascript: void()' data-bind='click: participantReady'>Ok, I am ready to start</a> + </li> +</ul> +</script><script type='text/html' id='WAITING_ROOM'><h3>Waiting for other participants</h3><div> @@ -116,7 +170,7 @@ <h4>Cash payment</h4><p> If you collect enough tokens to pay living expenses until the end of the session you will be paid in cash -<strong data-bind='text: formatCurrency(dollarsPerToken())'></strong> for each token you have. It is possible that you +<strong data-bind='text: formatCurrency(exchangeRate())'></strong> for each token you have. It is possible that you could earn as much as <strong data-bind='text: formatCurrency(maxEarnings())'></strong> for the entire experiment. However, the final outcome depends on your choices and those of your group members. </p> @@ -215,36 +269,6 @@ </li></ul></script> -<script type='text/html' id='PAID_EXPERIMENT_INSTRUCTIONS'> -<h2>Paid Experiment Instructions</h2> -<h3>Two Sessions</h3> -<p> -This experiment is composed of two different, unconnected sessions. Your group will be randomly selected for each -session, so you will be playing with a different group each time. We will pay you for one of these two sessions, chosen -at random. You have exactly 50% chance of being paid for your earnings in either session. -</p> -<h3>Group and Individual Status</h3> -<p> -You will be able to observe the status of the members of your group each round. Likewise your group members can see -your status and those of the group. -</p> -<h3>Group Chat</h3> -<p> -You will be able to chat with the other members of your group via group text chat. Once you have made a harvest -decision, you will no longer be able to chat for that round. -</p> -<h3>Harvest Choice</h3> -<p> -You will have a maximum of <i class='icon-clock'></i><span data-bind='text: roundDuration'></span> seconds to make a -harvest decision each round. A countdown will alert you when there are -<span data-bind='text: warningCountdownTime'></span> seconds remaining to make a harvest choice. When the countdown -reaches zero, any value you have selected will be submitted. <strong>The default harvest is zero.</strong> -</p> -</script> -<script type='text/html' id='INSTRUCTIONS'> - <div data-bind='html: instructions'> - </div> -</script><script type='text/html' id='REGULAR'><div class='row'><div class='span5'> @@ -381,6 +405,9 @@ var model = ko.mapping.fromJS(experimentModelJson); model.secondsLeft = ko.observable(0); model.currentInterval = ko.observable(); + model.totalEarnings = ko.computed(function() { + return formatCurrency(model.storage() * model.exchangeRate()); + }); model.templateId = ko.computed(function() { switch ( model.templateName() ) { case 'PRACTICE': diff -r 39c0b2f6304b71699416df6cb1c9928e458dd21f -r ae8d446dae622ca73a4fc54a3fbcce6dc16d16f7 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -69,8 +69,9 @@ 'maximumResourcesToDisplay': 20, 'warningCountdownTime': 10, 'harvestDecision': 0, + 'roundDuration': 60, 'chatMessages': [], - 'instructionsRound': False, + 'isInstructionsRound': False, } # FIXME: need to distinguish between instructions / welcome rounds and practice/regular rounds def get_view_model_json(experiment, participant_group_relationship, **kwargs): @@ -82,15 +83,15 @@ experiment_model_dict = experiment.to_dict(include_round_data=False, default_value_dict=experiment_model_defaults) # round / experiment configuration data - experiment_model_dict['roundDuration'] = current_round.duration experiment_model_dict['timeRemaining'] = experiment.time_remaining + experiment_model_dict['sessionId'] = current_round.session_id regrowth_rate = get_regrowth_rate(current_round) cost_of_living = get_cost_of_living(current_round) experiment_model_dict['costOfLiving'] = cost_of_living experiment_model_dict['maxHarvestDecision'] = get_max_allowed_harvest_decision(participant_group_relationship, current_round_data, ec) # instructions round parameters if current_round.is_instructions_round: - experiment_model_dict['instructionsRound'] = True + experiment_model_dict['isInstructionsRound'] = True experiment_model_dict['participantsPerGroup'] = ec.max_group_size experiment_model_dict['regrowthRate'] = regrowth_rate experiment_model_dict['initialResourceLevel'] = get_initial_resource_level(current_round) @@ -149,6 +150,4 @@ }) experiment_model_dict['groupData'] = group_data -# FIXME: defaults hard coded in for now - experiment_model_dict['instructions'] = current_round.get_custom_instructions() return dumps(experiment_model_dict) diff -r 39c0b2f6304b71699416df6cb1c9928e458dd21f -r ae8d446dae622ca73a4fc54a3fbcce6dc16d16f7 vcweb/core/ajax.py --- a/vcweb/core/ajax.py +++ b/vcweb/core/ajax.py @@ -111,7 +111,8 @@ def experiment_controller(request, pk, action=None): experiment = _get_experiment(request, pk) try: - experiment.invoke(action) + response_tuples = experiment.invoke(action) + logger.debug("invoking action %s, results: %s", action, str(response_tuples)) return experiment.to_json() except AttributeError as e: logger.warning("no attribute %s on experiment %s (%s)", action, experiment.status_line, e) diff -r 39c0b2f6304b71699416df6cb1c9928e458dd21f -r ae8d446dae622ca73a4fc54a3fbcce6dc16d16f7 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -766,9 +766,8 @@ else: logger.debug("no existing groups, proceeding") # seed the initial group. - current_group = self.group_set.create(number=self.group_set.count(), max_size=max_group_size, session_id=session_id) for p in participants: - pgr = self.add_participant(p, current_group, max_group_size) + pgr = self.add_participant(p, max_group_size=max_group_size) current_group = pgr.group self.create_group_clusters() @@ -807,7 +806,7 @@ 'deactivate', 'complete', 'restart_round', 'restart') def invoke(self, action_name): if action_name in Experiment.ACCEPTABLE_ACTIONS: - getattr(self, action_name)() + return getattr(self, action_name)() else: raise AttributeError("Invalid experiment action %s requested of experiment %s" % (action_name, self)) @@ -816,7 +815,7 @@ self.end_round() if self.has_next_round: self.current_round_sequence_number += 1 - self.start_round() + return self.start_round() else: logger.warning("trying to advance past the last round - no-op") @@ -835,18 +834,21 @@ def start_round(self, sender=None): logger.debug("%s STARTING ROUND (sender: %s)", self, sender) self.status = Experiment.Status.ROUND_IN_PROGRESS + current_round_configuration = self.current_round + if current_round_configuration.randomize_groups: + self.allocate_groups( + preserve_existing_groups=current_round_configuration.preserve_existing_groups, + session_id=current_round_configuration.session_id) + # XXX: must create round data AFTER group allocation so that any participant round data values + # (participant ready parameters for instance) are associated with the correct participant group + # relationships. self.create_round_data() self.current_round_start_time = datetime.now() + self.log('Starting round') self.save() - self.log('Starting round') - current_round_configuration = self.current_round - if current_round_configuration.randomize_groups: - self.allocate_groups(preserve_existing_groups=current_round_configuration.preserve_existing_groups, - session_id=current_round_configuration.session_id) + # notify registered game handlers if sender is None: sender = intern(self.experiment_metadata.namespace.encode('utf8')) - # notify registered game handlers - logger.debug("About to send round started signal with sender %s", sender) return signals.round_started.send_robust(sender, experiment=self, time=datetime.now(), round_configuration=current_round_configuration) def stop_round(self, sender=None, **kwargs): @@ -925,7 +927,7 @@ 'isRoundInProgress': self.is_round_in_progress, 'isActive': self.is_active, 'isArchived': self.is_archived, - 'dollarsPerToken': float(ec.exchange_rate), + 'exchangeRate': float(ec.exchange_rate), 'readyParticipants': self.number_of_ready_participants, 'totalNumberOfParticipants': self.participant_set.count(), } @@ -1048,6 +1050,9 @@ return RoundConfiguration.ROUND_TYPES_DICT[self.round_type][1] def get_custom_instructions(self, context_dict=None, **kwargs): + ''' + FIXME: deprecated in favor of RoundConfiguration.template_id approach + ''' if not self.is_instructions_round: logger.warning("tried to get custom instructions for a non-instructions round %s", self) return None Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-28 05:39:34
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/7410a47b1cf4/ Changeset: 7410a47b1cf4 User: alllee Date: 2013-03-28 05:53:11 Summary: clarifying logic Affected #: 1 file diff -r 4d5148cba04547c8278f4e3bfce0d15cc68e2101 -r 7410a47b1cf4acab39378fdc9b998ff82e95ae3d vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -455,7 +455,12 @@ model.setCurrentInterval( setInterval(function() { model.tick(); - model.setFormDisabled("#vcweb-form", model.secondsLeft() > 30); + if (model.secondsLeft() > 30 && ! model.isPracticeRound()) { + model.disableHarvestForm(); + } + else { + model.enableHarvestForm(); + } if (! model.isTimerRunning()) { model.submitDecision(); model.clearCurrentInterval(); @@ -465,11 +470,10 @@ } }; model.submitDecision = function(data, evt) { - model.setFormDisabled("#vcweb-form", false); + model.enableHarvestForm(); var formData = $('#vcweb-form').serialize(); - model.setFormDisabled("#vcweb-form", true); - model.disableChat(); - model.setFormDisabled("#chat-form", true); + model.disableHarvestForm(); + model.disableChatForm(); console.debug(formData); $.post('submit-harvest-decision', formData, function(response) { console.log(response); @@ -520,11 +524,7 @@ model.setFormDisabled("#chat-form", true); } model.setupChat = function() { - chatEnabled = model.chatEnabled(); - model.setFormDisabled("#chat-form", ! chatEnabled); - if (chatEnabled) { - model.disableHarvestForm(); - } + model.setFormDisabled("#chat-form", ! model.chatEnabled()); } model.afterRenderTemplate = function(elements) { if (model.templateId() === "REGULAR") { https://bitbucket.org/virtualcommons/vcweb/commits/39c0b2f6304b/ Changeset: 39c0b2f6304b User: alllee Date: 2013-03-28 06:39:17 Summary: wiring up all_participants_submitted to the experimenter Affected #: 6 files diff -r 7410a47b1cf4acab39378fdc9b998ff82e95ae3d -r 39c0b2f6304b71699416df6cb1c9928e458dd21f vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -300,7 +300,7 @@ </div></div><h3>Forest</h3> -<div data-bind='if: practiceRound'> +<div data-bind='if: isPracticeRound'><div class='alert alert-error alert-block'><h4>PRACTICE ROUND</h4> This is a practice round. The decisions you make in this round will <b>NOT</b> contribute to your earnings. @@ -477,6 +477,10 @@ console.debug(formData); $.post('submit-harvest-decision', formData, function(response) { console.log(response); + console.log("all participants ready?"); + if (response.all_participants_submitted) { + getWebSocket().send(createAllParticipantsReadyEvent()); + } model.update($.parseJSON(response.experimentModelJson)); // FIXME: forward the response message to the chat window should be handled completely on the server // side instead of ping-ponging to the client side back to the real time server back out to all diff -r 7410a47b1cf4acab39378fdc9b998ff82e95ae3d -r 39c0b2f6304b71699416df6cb1c9928e458dd21f vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -7,7 +7,8 @@ from vcweb.boundaries.forms import SingleIntegerDecisionForm from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_max_allowed_harvest_decision, get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, - get_last_harvest_decision, get_harvest_decision_dv, set_harvest_decision, can_observe_other_group, get_player_status) + get_last_harvest_decision, get_harvest_decision_dv, get_harvest_decision_parameter, set_harvest_decision, + can_observe_other_group, get_player_status) import logging logger = logging.getLogger(__name__) @@ -21,7 +22,6 @@ if experiment.experiment_metadata != get_experiment_metadata() or pgr.participant != request.user.participant: raise Http404 return render(request, 'boundaries/participate.html', { - 'auth_token': participant.authentication_token, 'experiment': experiment, 'participant_experiment_relationship': experiment.get_participant_experiment_relationship(participant), 'participant_group_relationship': pgr, @@ -36,11 +36,17 @@ participant_group_id = form.cleaned_data['participant_group_id'] pgr = get_object_or_404(ParticipantGroupRelationship, pk=participant_group_id) harvest_decision = form.cleaned_data['integer_decision'] - set_harvest_decision(pgr, harvest_decision, experiment.current_round_data, submitted=True) + round_data = experiment.current_round_data + set_harvest_decision(pgr, harvest_decision, round_data, submitted=True) message = "%s harvested %s trees" experiment.log(message % (pgr.participant, harvest_decision)) - return JsonResponse(dumps({ 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr), - 'message': message % (pgr.participant_handle, harvest_decision)})) + response_dict = { + 'success': True, + 'experimentModelJson': get_view_model_json(experiment, pgr), + 'message': message % (pgr.participant_handle, harvest_decision), + 'all_participants_submitted': experiment.all_participants_submitted(get_harvest_decision_parameter(), round_data) + } + return JsonResponse(dumps(response_dict)) else: logger.debug("form was invalid: %s", form) for field in form: @@ -92,7 +98,7 @@ experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk experiment_model_dict['templateName'] = current_round.template_name - experiment_model_dict['practiceRound'] = current_round.is_practice_round + experiment_model_dict['isPracticeRound'] = current_round.is_practice_round if current_round.is_regular_round: experiment_model_dict['chatEnabled'] = current_round.chat_enabled diff -r 7410a47b1cf4acab39378fdc9b998ff82e95ae3d -r 39c0b2f6304b71699416df6cb1c9928e458dd21f vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -545,6 +545,11 @@ else: return 0 + def all_participants_submitted(self, parameter, round_data=None): + if round_data is None: + round_data = self.current_round_data + return ParticipantRoundDataValue.objects.filter(parameter=parameter, submitted=True, round_data=round_data).count() == self.participant_set.count() + @property def all_participants_ready(self): return self.number_of_ready_participants == self.participant_set.count() diff -r 7410a47b1cf4acab39378fdc9b998ff82e95ae3d -r 39c0b2f6304b71699416df6cb1c9928e458dd21f vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -260,6 +260,15 @@ model.setCurrentInterval( setInterval( model.tick, 1000 ) ); } }; + model.nextRound = function() { + $('#progress-modal').modal('show'); + Dajaxice.vcweb.core.experiment_controller(function(data) { + ko.mapping.fromJS(data, model); + model.startTimer(); + sendUpdateEvent(); + $('#progress-modal').modal('hide'); + }, {pk: {{experiment.pk}}, 'action':"advance_to_next_round"}); + } model.confirmExperimentControllerAction = function(shouldUpdateParticipants, localModel, evt) { element = evt.target; console.debug(element); @@ -327,6 +336,8 @@ case 'update': console.debug("FIXME: ignoring update requests, patch sockjs broadcast to not send certain messages"); break; + case 'all_participants_ready': + experimentModel.nextRound(); case 'chat': case 'info': default: diff -r 7410a47b1cf4acab39378fdc9b998ff82e95ae3d -r 39c0b2f6304b71699416df6cb1c9928e458dd21f vcweb/core/templates/includes/participant.events.html --- a/vcweb/core/templates/includes/participant.events.html +++ b/vcweb/core/templates/includes/participant.events.html @@ -5,6 +5,9 @@ function createReconnectionEvent() { return createMessageEvent("Reconnecting from disconnect", "reconnect"); } +function createAllParticipantsReadyEvent() { + return createMessageEvent("All participants ready", "all_participants_ready"); +} function createMessageEvent(payload, event_type) { if (! event_type) { event_type = "chat"; diff -r 7410a47b1cf4acab39378fdc9b998ff82e95ae3d -r 39c0b2f6304b71699416df6cb1c9928e458dd21f vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -281,6 +281,15 @@ def handle_submit(self, event, experiment, **kwargs): pass + def handle_all_participants_ready(self, event, experiment, **kwargs): + logger.debug("all participants ready to move on to the next round for %s", experiment) + (per, valid) = self.verify_auth_token(event) + if valid: + connection_manager.send_to_experimenter(create_message_event("All participants are ready to move on to the next round.", event_type="all_participants_ready"), experiment=experiment) + else: + logger.warning("Invalid auth token for participant %s", per) + self.send(UNAUTHORIZED_EVENT) + def handle_client_ready(self, event, experiment, **kwargs): logger.debug("handling client ready event %s for experiment %s", event, experiment) (per, valid) = self.verify_auth_token(event) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-28 04:42:09
|
1 new commit in irrigation: https://bitbucket.org/virtualcommons/irrigation/commits/f51bc308f518/ Changeset: f51bc308f518 Branch: stable User: alllee Date: 2013-03-28 05:41:55 Summary: setting compiler target explicitly on ant javac Affected #: 1 file diff -r 8ff3c9cf0274dfeba84d50a6787b41b752235ce7 -r f51bc308f518b6cb3560877dc9aecd5029973320 build.xml --- a/build.xml +++ b/build.xml @@ -241,6 +241,7 @@ deprecation="on" includeantruntime='true' source="1.6" + target="1.6" ><compilerarg value='-Xlint:unchecked'/><classpath refid="project.classpath" /> @@ -316,6 +317,7 @@ <javac srcdir="${test.src.dir}" destdir="${test.build.dir}" source="1.6" + target="1.6" debug="on"><!-- <compilerarg value='-Xlint:unchecked'/> --><classpath refid="project.classpath" /> Repository URL: https://bitbucket.org/virtualcommons/irrigation/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-28 04:40:44
|
2 new commits in foraging: https://bitbucket.org/virtualcommons/foraging/commits/91a29135b11f/ Changeset: 91a29135b11f Branch: stable User: alllee Date: 2013-03-28 05:39:16 Summary: kw expansion Affected #: 33 files diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/data/AggregateCollectedTokenNeighborProcessor.java --- a/src/main/java/edu/asu/commons/foraging/data/AggregateCollectedTokenNeighborProcessor.java +++ b/src/main/java/edu/asu/commons/foraging/data/AggregateCollectedTokenNeighborProcessor.java @@ -23,7 +23,7 @@ import edu.asu.commons.util.Utils; /** - * $Id: AggregateCollectedTokenNeighborProcessor.java 526 2010-08-06 01:25:27Z alllee $ + * $Id$ * * Generates aggregate distributions of the number of neighboring tokens for a collected token in two situations: * 1. without regard to visibility diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/data/ClientMovementStatistics.java --- a/src/main/java/edu/asu/commons/foraging/data/ClientMovementStatistics.java +++ b/src/main/java/edu/asu/commons/foraging/data/ClientMovementStatistics.java @@ -5,7 +5,7 @@ import edu.asu.commons.net.Identifier; /** - * $Id: ClientMovementStatistics.java 526 2010-08-06 01:25:27Z alllee $ + * $Id$ * * Helper class to keep track of client movements. * diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/data/ClientMovementTokenCount.java --- a/src/main/java/edu/asu/commons/foraging/data/ClientMovementTokenCount.java +++ b/src/main/java/edu/asu/commons/foraging/data/ClientMovementTokenCount.java @@ -7,7 +7,7 @@ import edu.asu.commons.net.Identifier; /** - * $Id: ClientMovementTokenCount.java 526 2010-08-06 01:25:27Z alllee $ + * $Id$ * * Helper class for maintaining basic movement / token information. * diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java --- a/src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java +++ b/src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java @@ -9,7 +9,7 @@ import edu.asu.commons.experiment.SaveFileProcessor; /** - * $Id: ForagingSaveFileConverter.java 526 2010-08-06 01:25:27Z alllee $ + * $Id$ * <p> * Save file processors used to convert binary data files from the foraging experiment. * diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/data/MovementStatisticsProcessor.java --- a/src/main/java/edu/asu/commons/foraging/data/MovementStatisticsProcessor.java +++ b/src/main/java/edu/asu/commons/foraging/data/MovementStatisticsProcessor.java @@ -19,7 +19,7 @@ import edu.asu.commons.util.Utils; /** - * $Id: MovementStatisticsProcessor.java 526 2010-08-06 01:25:27Z alllee $ + * $Id$ * * * @author <a href='mailto:all...@as...'>Allen Lee</a> diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/BeginChatRoundRequest.java --- a/src/main/java/edu/asu/commons/foraging/event/BeginChatRoundRequest.java +++ b/src/main/java/edu/asu/commons/foraging/event/BeginChatRoundRequest.java @@ -6,13 +6,13 @@ /** - * $Id: BeginChatRoundRequest.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * * The facilitator uses this Request to signal the server that the timed * communication can now begin. * * @author Allen Lee - * @version $Revision: 4 $ + * @version $Revision$ */ public class BeginChatRoundRequest extends AbstractEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/ClientMovementRequest.java --- a/src/main/java/edu/asu/commons/foraging/event/ClientMovementRequest.java +++ b/src/main/java/edu/asu/commons/foraging/event/ClientMovementRequest.java @@ -10,13 +10,13 @@ /** - * $Id: ClientMovementRequest.java 350 2009-10-30 22:18:42Z alllee $ + * $Id$ * * Client signal informing the server that the client has moved in Direction d * and has ended up at Point p. * * @author <a href='mailto:al...@cs...'>Allen Lee</a> - * @version $Revision: 350 $ + * @version $Revision$ */ public class ClientMovementRequest extends AbstractEvent implements ClientRequest { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/ClientPoseUpdate.java --- a/src/main/java/edu/asu/commons/foraging/event/ClientPoseUpdate.java +++ b/src/main/java/edu/asu/commons/foraging/event/ClientPoseUpdate.java @@ -5,10 +5,10 @@ import edu.asu.commons.net.Identifier; /** - * $Id: ClientPoseUpdate.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * * @author <a href='All...@as...'>Allen Lee</a>, Deepali Bhagvat - * @version $Revision: 4 $ + * @version $Revision$ */ public class ClientPoseUpdate extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/CollectTokenRequest.java --- a/src/main/java/edu/asu/commons/foraging/event/CollectTokenRequest.java +++ b/src/main/java/edu/asu/commons/foraging/event/CollectTokenRequest.java @@ -4,12 +4,12 @@ import edu.asu.commons.net.Identifier; /** - * $Id: CollectTokenRequest.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * * Signals that the client wants to collect a token at its present location. * * @author <a href='All...@as...'>Allen Lee</a> - * @version $Revision: 4 $ + * @version $Revision$ */ public class CollectTokenRequest extends AbstractEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/EndRoundEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/EndRoundEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/EndRoundEvent.java @@ -11,7 +11,7 @@ /** - * $Id: EndRoundEvent.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * * This event carries all data relevant to the ending of a round, including the * debriefing message, the time (in milliseconds) that the client should wait @@ -21,7 +21,7 @@ * * @author Deepali Bhagvat * @author Allen Lee - * @version $Revision: 4 $ + * @version $Revision$ */ public class EndRoundEvent extends AbstractEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/EnforcementRankingRequest.java --- a/src/main/java/edu/asu/commons/foraging/event/EnforcementRankingRequest.java +++ b/src/main/java/edu/asu/commons/foraging/event/EnforcementRankingRequest.java @@ -5,13 +5,13 @@ import edu.asu.commons.net.Identifier; /** - * $Id: EnforcementRankingRequest.java 522 2010-06-30 19:17:48Z alllee $ + * $Id$ * * Sent from a client to the server signaling that the client * has updated the votes to the given options * * @author <a href='all...@as...'>Allen Lee</a> - * @version $Revision: 522 $ + * @version $Revision$ */ public class EnforcementRankingRequest extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/ExplicitCollectionModeRequest.java --- a/src/main/java/edu/asu/commons/foraging/event/ExplicitCollectionModeRequest.java +++ b/src/main/java/edu/asu/commons/foraging/event/ExplicitCollectionModeRequest.java @@ -6,12 +6,12 @@ /** - * $Id: ExplicitCollectionModeRequest.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * * Informs the server that the client's collection mode has changed. * * @author <a href='All...@as...'>Allen Lee</a> - * @version $Revision: 4 $ + * @version $Revision$ */ public class ExplicitCollectionModeRequest extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/MovementEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/MovementEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/MovementEvent.java @@ -6,9 +6,9 @@ /** - * $Id: MovementEvent.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * - * @version $Revision: 4 $ + * @version $Revision$ * @author Allen Lee */ public class MovementEvent extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/PostRoundSanctionRequest.java --- a/src/main/java/edu/asu/commons/foraging/event/PostRoundSanctionRequest.java +++ b/src/main/java/edu/asu/commons/foraging/event/PostRoundSanctionRequest.java @@ -11,7 +11,7 @@ * Carries a Map tying Identifiers to integer sanction amounts (can be positive or negative). * * @author alllee - * @version $Revision: 4 $ + * @version $Revision$ */ public class PostRoundSanctionRequest extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/QuizCompletedEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/QuizCompletedEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/QuizCompletedEvent.java @@ -5,10 +5,10 @@ /** - * $Id: QuizCompletedEvent.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * * @author Allen Lee - * @version $Revision: 4 $ + * @version $Revision$ */ public class QuizCompletedEvent extends AbstractEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/QuizResponseEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/QuizResponseEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/QuizResponseEvent.java @@ -8,7 +8,7 @@ import edu.asu.commons.net.Identifier; /** - * $Id: QuizResponseEvent.java 522 2010-06-30 19:17:48Z alllee $ + * $Id$ * * A client's quiz responses for a given quiz page. * diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/RealTimeSanctionRequest.java --- a/src/main/java/edu/asu/commons/foraging/event/RealTimeSanctionRequest.java +++ b/src/main/java/edu/asu/commons/foraging/event/RealTimeSanctionRequest.java @@ -6,12 +6,12 @@ /** - * $Id: RealTimeSanctionRequest.java 492 2010-03-23 23:08:38Z alllee $ + * $Id$ * * A request made by a client to sanction another client. * * @author <a href='mailto:all...@as...'>Allen Lee</a>, Deepali Bhagvat - * @version $Revision: 492 $ + * @version $Revision$ */ public class RealTimeSanctionRequest extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/ResourceAddedEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/ResourceAddedEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/ResourceAddedEvent.java @@ -8,12 +8,12 @@ import edu.asu.commons.net.Identifier; /** - * $Id: ResourceAddedEvent.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * FoodAddedEvent * * @author Allen Lee * @author Deepali Bhagvat - * @version $Revision: 4 $ + * @version $Revision$ */ public class ResourceAddedEvent extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/ResourcesAddedEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/ResourcesAddedEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/ResourcesAddedEvent.java @@ -10,11 +10,11 @@ import edu.asu.commons.net.Identifier; /** - * $Id: ResourcesAddedEvent.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * FoodAddedEvent * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 4 $ + * @version $Revision$ */ public class ResourcesAddedEvent extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/RoundStartedEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/RoundStartedEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/RoundStartedEvent.java @@ -10,7 +10,7 @@ /** - * $Id: RoundStartedEvent.java 497 2010-03-29 20:10:49Z alllee $ + * $Id$ * * Signals clients that the beginning of a round has begun, carrying * relevant round parameters so the client can initialize its game window @@ -18,7 +18,7 @@ * * * @author <a href='mailto:all...@as...'>Allen Lee</a> - * @version $Revision: 497 $ + * @version $Revision$ */ public class RoundStartedEvent extends AbstractEvent implements ExperimentUpdateEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/SanctionAppliedEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/SanctionAppliedEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/SanctionAppliedEvent.java @@ -4,7 +4,7 @@ import edu.asu.commons.net.Identifier; /** - * $Id: SanctionAppliedEvent.java 522 2010-06-30 19:17:48Z alllee $ + * $Id$ * * Persistable event marking an applied sanction. * diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/SynchronizeClientEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/SynchronizeClientEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/SynchronizeClientEvent.java @@ -12,7 +12,7 @@ /** - * $Id: SynchronizeClientEvent.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * * Maintains a Map of all clients and their locations (denoted by * java.awt.Point-S) as well as a list of food positions, if the food is visible. @@ -21,7 +21,7 @@ * * @author Deepali Bhagvat * @author Allen Lee - * @version $Revision: 4 $ + * @version $Revision$ */ public class SynchronizeClientEvent extends AbstractEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/TokenBirthEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/TokenBirthEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/TokenBirthEvent.java @@ -6,12 +6,12 @@ import edu.asu.commons.net.Identifier; /** - * $Id: TokenBirthEvent.java 78 2009-03-03 03:36:25Z alllee $ + * $Id$ * * Signifies that a resource at location source gave "birth" at location offspring. * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 78 $ + * @version $Revision$ */ public class TokenBirthEvent extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/TokenCollectedEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/TokenCollectedEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/TokenCollectedEvent.java @@ -6,13 +6,13 @@ import edu.asu.commons.net.Identifier; /** - * $Id: TokenCollectedEvent.java 78 2009-03-03 03:36:25Z alllee $ + * $Id$ * * Persistable event signifying that a token was collected at some Point getLocation() by * the participant with Identifier getId(). * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 78 $ + * @version $Revision$ */ public class TokenCollectedEvent extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/TokenMovedEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/TokenMovedEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/TokenMovedEvent.java @@ -5,12 +5,12 @@ import edu.asu.commons.event.AbstractPersistableEvent; import edu.asu.commons.net.Identifier; /** - * $Id: TokenMovedEvent.java 78 2009-03-03 03:36:25Z alllee $ + * $Id$ * * Signifies that a token moved from source to destination. * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 78 $ + * @version $Revision$ */ public class TokenMovedEvent extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/event/TokensMovedEvent.java --- a/src/main/java/edu/asu/commons/foraging/event/TokensMovedEvent.java +++ b/src/main/java/edu/asu/commons/foraging/event/TokensMovedEvent.java @@ -6,13 +6,13 @@ import edu.asu.commons.event.AbstractPersistableEvent; import edu.asu.commons.net.Identifier; /** - * $Id: TokensMovedEvent.java 78 2009-03-03 03:36:25Z alllee $ + * $Id$ * * Bulk token movement event containing old locations that should be removed and * the new locations that should be added. * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 78 $ + * @version $Revision$ */ public class TokensMovedEvent extends AbstractPersistableEvent { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/facilitator/GroupView.java --- a/src/main/java/edu/asu/commons/foraging/facilitator/GroupView.java +++ b/src/main/java/edu/asu/commons/foraging/facilitator/GroupView.java @@ -11,7 +11,7 @@ import edu.asu.commons.foraging.ui.GridView; /** - * $Id: GroupView.java 510 2010-04-20 04:11:22Z alllee $ + * $Id$ * * Provides an overview visualization of a particular group and all participants in the group. * diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/model/Direction.java --- a/src/main/java/edu/asu/commons/foraging/model/Direction.java +++ b/src/main/java/edu/asu/commons/foraging/model/Direction.java @@ -5,12 +5,12 @@ import java.util.Random; /** - * $Id: Direction.java 4 2008-07-25 22:51:44Z alllee $ + * $Id$ * * Enum representing a cardinal Direction in a 2-D grid. * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 4 $ + * @version $Revision$ */ public enum Direction { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/model/RegulationData.java --- a/src/main/java/edu/asu/commons/foraging/model/RegulationData.java +++ b/src/main/java/edu/asu/commons/foraging/model/RegulationData.java @@ -5,13 +5,13 @@ import edu.asu.commons.net.Identifier; /** - * $Id: RegulationData.java 416 2009-12-25 05:17:14Z alllee $ + * $Id$ * * Prototype object used to carry information about a regulation proposed * by a participant. * * @author <a href='mailto:db...@as...'>dbarge</a> - * @version $Revision: 416 $ + * @version $Revision$ */ public class RegulationData implements Serializable, Comparable<RegulationData> { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/model/ResourceGenerator.java --- a/src/main/java/edu/asu/commons/foraging/model/ResourceGenerator.java +++ b/src/main/java/edu/asu/commons/foraging/model/ResourceGenerator.java @@ -8,12 +8,12 @@ import edu.asu.commons.foraging.conf.RoundConfiguration; /** - * $Id: ResourceGenerator.java 475 2010-02-24 00:39:44Z alllee $ + * $Id$ * * ResourceGenerators add resources directly to the GroupDataModel. * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 475 $ + * @version $Revision$ */ public interface ResourceGenerator { public void initialize(RoundConfiguration roundConfiguration); diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/model/StochasticGenerator.java --- a/src/main/java/edu/asu/commons/foraging/model/StochasticGenerator.java +++ b/src/main/java/edu/asu/commons/foraging/model/StochasticGenerator.java @@ -1,12 +1,12 @@ package edu.asu.commons.foraging.model; /** - * $Id: StochasticGenerator.java 76 2009-02-25 18:02:38Z alllee $ + * $Id$ * * * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 76 $ + * @version $Revision$ */ public interface StochasticGenerator extends ResourceGenerator { public double getProbabilityForCell(GroupDataModel group, int x, int y); diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/ui/GameWindow.java --- a/src/main/java/edu/asu/commons/foraging/ui/GameWindow.java +++ b/src/main/java/edu/asu/commons/foraging/ui/GameWindow.java @@ -5,12 +5,12 @@ import edu.asu.commons.foraging.event.EndRoundEvent; /** - * $Id: GameWindow.java 416 2009-12-25 05:17:14Z alllee $ + * $Id$ * * Marker interface for both 2d and 3d game windows. * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 416 $ + * @version $Revision$ */ public interface GameWindow { diff -r d76a4a1439269f24f331741b86d1811977e0c33d -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 src/main/java/edu/asu/commons/foraging/ui/PostRoundSanctioningPanel.java --- a/src/main/java/edu/asu/commons/foraging/ui/PostRoundSanctioningPanel.java +++ b/src/main/java/edu/asu/commons/foraging/ui/PostRoundSanctioningPanel.java @@ -51,7 +51,7 @@ * Customized JPanel that enables participants to engage in post-round sanctioning. * * @author <a href='mailto:All...@as...'>Allen Lee</a> - * @version $Revision: 384 $ + * @version $Revision$ */ @SuppressWarnings("serial") https://bitbucket.org/virtualcommons/foraging/commits/9a85c86b5535/ Changeset: 9a85c86b5535 Branch: stable User: alllee Date: 2013-03-28 05:39:55 Summary: merging default back into stable Affected #: 13 files diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 build.xml --- a/build.xml +++ b/build.xml @@ -84,7 +84,7 @@ test - Run all JUnit in the test source tree. build-all - builds the client, server, and facilitator jars. deploy - invokes build-all and then copies the client and facilitator jars to ${web.dir} - convert - invokes the ForagingSaveFileConverter to process the savefiles in the raw-data directory or as specified by -Dsavefile.dir=foo + convert - invokes the ForagingSaveFileConverter to process the savefiles in the experiment-data directory or as specified by -Dsavefile.dir=foo </echo></target><target name="build-all" depends="facilitator-jar, client-jar, server-jar, compile"/> @@ -202,7 +202,7 @@ </target><!-- Compile project source files --><target name="compile" depends="prepare, resolve"> - <javac srcdir="${src.dir}" destdir="${build.dir}" debug="on" optimize="off" deprecation="on" source="1.6" includeAntRuntime="false"> + <javac srcdir="${src.dir}" destdir="${build.dir}" debug="on" optimize="off" deprecation="on" source="1.6" target="1.6" includeAntRuntime="false"><compilerarg value="-Xlint:unchecked"/><classpath refid="project.classpath"/></javac> @@ -260,7 +260,7 @@ </target><!-- Compile Tests --><target name="compile-tests" depends="compile"> - <javac srcdir="${test.src.dir}" destdir="${test.build.dir}" source="1.6" debug="on"> + <javac srcdir="${test.src.dir}" destdir="${test.build.dir}" source="1.6" target="1.6" debug="on"><!-- <compilerarg value='-Xlint:unchecked'/> --><classpath refid="project.classpath"/></javac> @@ -281,8 +281,8 @@ </junit></target><property name="savefile.converter.class" value="edu.asu.commons.foraging.data.ForagingSaveFileConverter"/> - <!-- default savefile directory is the raw-data directory --> - <property name="savefile.dir" value="raw-data"/> + <!-- default savefile directory is the experiment-data directory --> + <property name="savefile.dir" value="experiment-data"/><target name="convert" depends="compile"><java classname="${savefile.converter.class}" classpathref="project.classpath" fork="yes"><arg value="${savefile.dir}"/> diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java --- a/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java +++ b/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java @@ -664,11 +664,12 @@ else if (resourceGeneratorType.equals("top-bottom-patchy")) { addSpecialInstructions(builder, getPatchyResourceInstructions()); } - if (builder.toString().isEmpty()) { + if (builder.length() == 0) { return instructionsBuilder; } else { - return instructionsBuilder.append("<h2>Additional instructions</h2><hr><ul>").append(builder).append("</ul>"); + // FIXME: localize via ResourceBundle + return instructionsBuilder.append("<hr><ul>").append(builder).append("</ul>"); } } @@ -685,7 +686,7 @@ } private String getInRoundChatInstructions() { - return getProperty("in-round-chat-instructions", "<p>You can chat during this round with all players visible on the screen.</p>"); + return getProperty("in-round-chat-instructions", getParentConfiguration().getInRoundChatInstructions()); } public String getTrustGameInstructions() { @@ -850,4 +851,29 @@ return getProperty("survey-confirmation-message", "Please make sure you have completed the survey before continuing. Have you completed the survey?"); } + + public String[] getTrustGamePlayerTwoColumnNames() { + return getParentConfiguration().getTrustGamePlayerTwoColumnNames(); + } + + public String getTrustGamePlayerOneAllocationLabel() { + return getParentConfiguration().getTrustGamePlayerOneAllocationLabel(); + } + + public String getTrustGamePlayerTwoAllocationLabel() { + return getParentConfiguration().getTrustGamePlayerTwoAllocationLabel(); + } + + public String getTrustGamePlayerTwoInstructionLabel() { + return getParentConfiguration().getTrustGamePlayerTwoInstructionLabel(); + } + + public String getPlayerOneAmountToKeepValidation() { + return getParentConfiguration().getPlayerOneAmountToKeepValidation(); + } + + public String getPlayerTwoAmountToKeepValidation() { + return getParentConfiguration().getPlayerTwoAmountToKeepValidation(); + } + } diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/conf/ServerConfiguration.java --- a/src/main/java/edu/asu/commons/foraging/conf/ServerConfiguration.java +++ b/src/main/java/edu/asu/commons/foraging/conf/ServerConfiguration.java @@ -110,7 +110,7 @@ } public double getDollarsPerToken() { - return DEFAULT_DOLLARS_PER_TOKEN; + return getDoubleProperty("dollars-per-token", DEFAULT_DOLLARS_PER_TOKEN); } public String getFinalRoundFacilitatorInstructions() { @@ -155,8 +155,41 @@ return getIntProperty("server-sleep-interval", 50); } + public String getInRoundChatInstructions() { + return getProperty("in-round-chat-instructions", "<p>You can chat during this round with all players visible on the screen.</p>"); + } + public String getWaitingRoomInstructions() { return getProperty("waiting-room-instructions", "<h1>Please wait</h1><hr><p>Please wait while the rest of the participants complete the task.</p>"); } + public String[] getTrustGamePlayerTwoColumnNames() { + return new String[] { + getProperty("trust-game-p2-column-0", "Amount sent by P1"), + getProperty("trust-game-p2-column-1", "Total amount received"), + getProperty("trust-game-p2-column-2", "Amount to keep"), + getProperty("trust-game-p2-column-3", "Amount to return to P1") + }; + } + + public String getTrustGamePlayerOneAllocationLabel() { + return getProperty("trust-game-p1-allocation", "Player 1: Please select one of the following allocations."); + } + + public String getTrustGamePlayerTwoAllocationLabel() { + return getProperty("trust-game-p2-allocation", "Player 2: Please enter data for ALL of the following allocations."); + } + + public String getTrustGamePlayerTwoInstructionLabel() { + return getProperty("trust-game-p2-amount-to-keep-label", "Click in the \"Amount to keep\" column to select how much to keep if you are selected as player 2."); + } + + public String getPlayerOneAmountToKeepValidation() { + return getProperty("trust-game-p1-validation", "Please select the amount you would like to keep as player 1."); + } + + public String getPlayerTwoAmountToKeepValidation() { + return getProperty("trust-game-p2-validation", "Please select the amount you would like to keep as player 1."); + } + } diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/data/AllDataProcessor.java --- a/src/main/java/edu/asu/commons/foraging/data/AllDataProcessor.java +++ b/src/main/java/edu/asu/commons/foraging/data/AllDataProcessor.java @@ -46,7 +46,6 @@ @Override public void process(SavedRoundData savedRoundData, PrintWriter writer) { - RoundConfiguration roundConfiguration = (RoundConfiguration) savedRoundData.getRoundParameters(); processData(savedRoundData, writer); } @@ -149,11 +148,13 @@ writer.println(line); } else if (event instanceof RuleVoteRequest) { + System.err.println("rule vote request: " + event); RuleVoteRequest request = (RuleVoteRequest) event; String line = String.format("%s, %s, %s, Strategy Nomination", savedRoundData.toSecondString(event), request.getId(), request.getRule()); writer.println(line); } else if (event instanceof RuleSelectedUpdateEvent) { + System.err.println("rule selected update event: " + event); RuleSelectedUpdateEvent update = (RuleSelectedUpdateEvent) event; String line = String.format("%s, %s, \"%s\", \"%s\", Rule selected", savedRoundData.toSecondString(event), update.getGroup(), update.getSelectedStrategies(), update.getVotingResults()); diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/data/ForagingRuleProcessor.java --- /dev/null +++ b/src/main/java/edu/asu/commons/foraging/data/ForagingRuleProcessor.java @@ -0,0 +1,175 @@ +package edu.asu.commons.foraging.data; + +import java.awt.Point; +import java.io.PrintWriter; +import java.util.Comparator; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeMap; + +import edu.asu.commons.event.PersistableEvent; +import edu.asu.commons.experiment.SaveFileProcessor.Base; +import edu.asu.commons.experiment.SavedRoundData; +import edu.asu.commons.foraging.event.TokenCollectedEvent; +import edu.asu.commons.foraging.model.ClientData; +import edu.asu.commons.foraging.model.ServerDataModel; +import edu.asu.commons.net.Identifier; + +public class ForagingRuleProcessor extends Base { + + // rules are based on ForagingStrategy enum and ordered accordingly + // rule 1: collect tokens for 10 seconds than wait 10 seconds + // rule 2: private property, 4 quadrants + // rule 3: wait 60 seconds + // rule 4: collect 40 tokens then wait 30 seconds + private static class RuleData { + private int illegalRuleOneTokens = 0; + private int illegalRuleThreeTokens = 0; + private int illegalRuleFourTokens = 0; + private int totalTokensCollected = 0; + private int q1Tokens = 0; + private int q2Tokens = 0; + private int q3Tokens = 0; + private int q4Tokens = 0; + private int nextLegalCollectionTime = -1; + private int ruleFourTokenInterval = 1; + + public void addTokenCollected(Point location, int elapsedTimeInSeconds) { + if (isIllegalTokenCollectionForRuleOne(elapsedTimeInSeconds)) { + illegalRuleOneTokens++; + } + if (isIllegalTokenCollectionForRuleThree(elapsedTimeInSeconds)) { + illegalRuleThreeTokens++; + } + totalTokensCollected++; + addRuleTwoTokens(location); + checkRuleFourTokens(elapsedTimeInSeconds); + } + + private void checkRuleFourTokens(int elapsedTimeInSeconds) { + if (isIllegalRuleFourInterval(elapsedTimeInSeconds)) { + illegalRuleFourTokens++; + } + } + + private boolean isIllegalRuleFourInterval(int elapsedTimeInSeconds) { + if (totalTokensCollected < 40) { + return false; + } + int allowedTokens = ruleFourTokenInterval * 40; + // first check if we've reached our token goal + if (totalTokensCollected == allowedTokens) { + // next allowable time is 30 seconds from now. + nextLegalCollectionTime = elapsedTimeInSeconds + 30; + // the next number of allowable tokens is N * 40 + ruleFourTokenInterval++; + } +// System.err.println(String.format("allowed tokens: %d, total tokens collected: %d, next legal collection time: %d, token interval %d, legal collection? %s", +// allowedTokens, +// totalTokensCollected, +// nextLegalCollectionTime, +// ruleFourTokenInterval, +// (elapsedTimeInSeconds < nextLegalCollectionTime))); + return elapsedTimeInSeconds < nextLegalCollectionTime; + } + + private void addRuleTwoTokens(Point location) { + if (location.x < 13) { + if (location.y < 13) { + q1Tokens++; + } + else { + q2Tokens++; + } + } + else { + if (location.y < 13) { + q3Tokens++; + } + else { + q4Tokens++; + } + } + } + + private boolean isIllegalTokenCollectionForRuleThree(int elapsedTimeInSeconds) { + return elapsedTimeInSeconds <= 60; + } + + /** + * Returns true if the elapsed time is in the following interval ranges: + * 0-10, 20-30, 40-50, 60-70, and so on. + * + * @param elapsedTimeInSeconds + * @return + */ + private boolean isIllegalTokenCollectionForRuleOne(int elapsedTimeInSeconds) { + int interval = elapsedTimeInSeconds / 10; + int intervalModTwo = interval % 2; + return intervalModTwo == 0; + } + + public double getRuleOneBreaking() { + return (double) illegalRuleOneTokens / (double) totalTokensCollected; + } + public double getRuleThreeBreaking() { + return (double) illegalRuleThreeTokens / (double) totalTokensCollected; + } + public double getRuleFourBreaking() { + return (double) illegalRuleFourTokens / (double) totalTokensCollected; + } + + @Override + public String toString() { + return String.format("illegal R1 tokens: %d, illegal R2 tokens: %d, total tokens: %d, [%d, %d, %d, %d]", + illegalRuleOneTokens, illegalRuleFourTokens, totalTokensCollected, q1Tokens, q2Tokens, q3Tokens, q4Tokens); + } + + } + + @Override + public String getOutputFileExtension() { + return "-rule-data.txt"; + } + + @Override + public void process(SavedRoundData savedRoundData, PrintWriter writer) { + SortedSet<PersistableEvent> actions = savedRoundData.getActions(); + ServerDataModel dataModel = (ServerDataModel) savedRoundData.getDataModel(); + Map<Identifier, ClientData> clientDataMap = dataModel.getClientDataMap(); + Map<ClientData, RuleData> dataMap = new TreeMap<ClientData, RuleData>(new Comparator<ClientData>() { + public int compare(ClientData a, ClientData b) { + return a.getId().getStationId().compareTo(b.getId().getStationId()); + } + }); + for (ClientData data: clientDataMap.values()) { + dataMap.put(data, new RuleData()); + } + for (PersistableEvent event: actions) { + if (event instanceof TokenCollectedEvent) { + TokenCollectedEvent tokenCollectedEvent = (TokenCollectedEvent) event; + ClientData clientData = clientDataMap.get(event.getId()); + Point location = tokenCollectedEvent.getLocation(); + long elapsedTimeInSeconds = savedRoundData.getElapsedTimeInSeconds(event); + dataMap.get(clientData).addTokenCollected(location, (int) elapsedTimeInSeconds); + } + } + writer.println("Participant, 10 Second Rule, 60 Second Rule, 40 Second Rule, Q1 Tokens, Q2 Tokens, Q3 Tokens, Q4 Tokens"); + for (Map.Entry<ClientData, RuleData> entry: dataMap.entrySet()) { + RuleData data = entry.getValue(); + String line = String.format("%s, %3.2f, %3.2f, %3.2f, %d, %d, %d, %d", + entry.getKey(), + data.getRuleOneBreaking(), + data.getRuleThreeBreaking(), + data.getRuleFourBreaking(), + data.q1Tokens, + data.q2Tokens, + data.q3Tokens, + data.q4Tokens + ); + System.err.println(line); + writer.println(line); + } + } + +} diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java --- a/src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java +++ b/src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java @@ -31,8 +31,9 @@ new AggregateTokenSpatialDistributionProcessor(), new CollectedTokenSpatialDistributionProcessor(), new MovementStatisticsProcessor(), +// new MovieCreatorProcessor(), + new ForagingRuleProcessor(), new AggregateCollectedTokenNeighborProcessor() - // new MovieCreatorProcessor() )); Persister.processSaveFiles(allSaveFilesDirectory, processors); return true; diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/data/MovieCreatorProcessor.java --- /dev/null +++ b/src/main/java/edu/asu/commons/foraging/data/MovieCreatorProcessor.java @@ -0,0 +1,158 @@ +package edu.asu.commons.foraging.data; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +import edu.asu.commons.event.PersistableEvent; +import edu.asu.commons.experiment.SaveFileProcessor; +import edu.asu.commons.experiment.SavedRoundData; +import edu.asu.commons.foraging.conf.RoundConfiguration; +import edu.asu.commons.foraging.event.AddClientEvent; +import edu.asu.commons.foraging.facilitator.GroupView; +import edu.asu.commons.foraging.model.GroupDataModel; +import edu.asu.commons.foraging.model.ServerDataModel; +import edu.asu.commons.foraging.util.IntervalChecker; +import edu.asu.commons.foraging.util.QuickTimeOutputStream; +import edu.asu.commons.foraging.util.VideoFormat; + +/** + * $Id$ + * + * Foraging save file processor to create quicktime movies. + * + * @author <a href='mailto:All...@as...'>Allen Lee</a> + * @version $Rev: 522 $ + */ +class MovieCreatorProcessor extends SaveFileProcessor.Base { + + private VideoFormat videoFormat; + + public MovieCreatorProcessor() { + this(VideoFormat.PNG); + } + + public MovieCreatorProcessor(VideoFormat videoFormat) { + this.videoFormat = videoFormat; + } + + @Override + public void process(SavedRoundData savedRoundData, OutputStream ignored) { + // there needs to be one output stream per group because we write 1 video per group. + // we ignore the incoming output stream. + ServerDataModel serverDataModel = (ServerDataModel) savedRoundData.getDataModel(); + RoundConfiguration roundConfiguration = (RoundConfiguration) savedRoundData.getRoundParameters(); + final List<GroupView> groupViewList = new ArrayList<GroupView>(); + final Map<GroupView, QuickTimeOutputStream> groupViewMap = new HashMap<GroupView, QuickTimeOutputStream>(); + serverDataModel.reinitialize(roundConfiguration); + List<JFrame> jframes = new ArrayList<JFrame>(); + Dimension dimension = new Dimension(800, 800); + File savedRoundDataFile = new File(savedRoundData.getSaveFilePath()); + String saveFilePath = savedRoundDataFile.getName(); + for (GroupDataModel groupDataModel: serverDataModel.getGroups()) { + GroupView groupView = new GroupView(dimension, groupDataModel); + groupView.setup(roundConfiguration); + groupViewList.add(groupView); + try { + File groupMovieFile = new File(savedRoundDataFile.getCanonicalPath() + "-group-" + groupDataModel.getGroupId() + ".mov"); + groupViewMap.put(groupView, new QuickTimeOutputStream(groupMovieFile, videoFormat)); + } + catch (IOException exception) { + exception.printStackTrace(); + } + JFrame jframe = new JFrame("Group: " + groupDataModel.getGroupId()); + jframe.add(groupView); + jframe.pack(); + jframe.setVisible(true); + jframes.add(jframe); + } + // grab out all add client events to initialize the state of the game properly. + for (PersistableEvent event: savedRoundData.getActions()) { + if (event instanceof AddClientEvent) { + System.err.println("Adding client: " + event); + serverDataModel.apply(event); + } + } + IntervalChecker intervalChecker = new IntervalChecker(); + // 10 frames per second + intervalChecker.setUnitsPerInterval(100); + + for (PersistableEvent event: savedRoundData.getActions()) { + final long elapsedTimeInMillis = savedRoundData.getElapsedTime(event); + + serverDataModel.apply(event); + if ( intervalChecker.isIntervalElapsed(elapsedTimeInMillis) && serverDataModel.isDirty() ) { + + for (final GroupView groupView: groupViewList) { + try { + // groupView.repaint(); + final Dimension groupViewSize = groupView.getSize(); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + Graphics2D graphics = (Graphics2D) groupView.getGraphics(); + BufferedImage bufferedImage = graphics.getDeviceConfiguration().createCompatibleImage(groupViewSize.width, groupViewSize.height); + Graphics2D bufferedImageGraphics = bufferedImage.createGraphics(); + groupView.paint(bufferedImageGraphics); + try { + // 600 time scale units = 1 s + // 10 fps = one frame per 60 time scale units + groupViewMap.get(groupView).writeFrame(bufferedImage, 60); + } + catch (IOException exception) { + exception.printStackTrace(); + throw new RuntimeException(exception); + } + } + }); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + serverDataModel.setDirty(false); + + } + + } + for (QuickTimeOutputStream out : groupViewMap.values()) { + try { + out.close(); + } + catch (IOException exception) { + exception.printStackTrace(); + } + } + for (JFrame jframe : jframes) { + jframe.setVisible(false); + jframe.dispose(); + } + groupViewMap.clear(); + } + + + @Override + public void process(SavedRoundData savedRoundData, PrintWriter writer) { + throw new UnsupportedOperationException("This method is not suitable for this class (consider removing as requirement for super class)"); + } + + @Override + public String getOutputFileExtension() { + String videoFormatString = videoFormat.toString().toLowerCase(); + return String.format("-%s-movie.%s", videoFormatString, videoFormatString); + } +} diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/data/SummaryProcessor.java --- a/src/main/java/edu/asu/commons/foraging/data/SummaryProcessor.java +++ b/src/main/java/edu/asu/commons/foraging/data/SummaryProcessor.java @@ -11,12 +11,17 @@ import java.util.TreeSet; import edu.asu.commons.event.ChatRequest; +import edu.asu.commons.event.PersistableEvent; import edu.asu.commons.experiment.SaveFileProcessor; import edu.asu.commons.experiment.SavedRoundData; +import edu.asu.commons.foraging.event.RuleSelectedUpdateEvent; +import edu.asu.commons.foraging.event.RuleVoteRequest; +import edu.asu.commons.foraging.event.SanctionAppliedEvent; +import edu.asu.commons.foraging.event.TokenCollectedEvent; import edu.asu.commons.foraging.model.ClientData; import edu.asu.commons.foraging.model.GroupDataModel; import edu.asu.commons.foraging.model.ServerDataModel; -import edu.asu.commons.util.Utils; +import edu.asu.commons.net.Identifier; /** * $Id$ @@ -30,9 +35,23 @@ public void process(SavedRoundData savedRoundData, PrintWriter writer) { ServerDataModel serverDataModel = (ServerDataModel) savedRoundData.getDataModel(); List<GroupDataModel> groups = serverDataModel.getOrderedGroups(); + for (PersistableEvent event: savedRoundData.getActions()) { + if (event instanceof SanctionAppliedEvent) { + SanctionAppliedEvent sanctionEvent = (SanctionAppliedEvent) event; + Identifier id = sanctionEvent.getId(); + System.err.println("applying sanction costs and penalties to " + sanctionEvent.getId() + " -> " + sanctionEvent.getTarget()); + ClientData source = serverDataModel.getClientData(id); + source.addSanctionCosts(sanctionEvent.getSanctionCost()); + System.err.println("costs on client data are now " + source.getSanctionCosts()); + ClientData target = serverDataModel.getClientData(sanctionEvent.getTarget()); + target.addSanctionPenalties(sanctionEvent.getSanctionPenalty()); + System.err.println("penalties on client data are now " + target.getSanctionPenalties()); + } + } + + writer.println("Participant, Group, Total Cumulative Tokens, Sanction costs, Sanction penalties"); for (GroupDataModel group: groups) { - int totalConsumedGroupTokens = 0; - ArrayList<String> clientTokens = new ArrayList<String>(); + int totalTokensHarvested = 0; ArrayList<ClientData> clientDataList = new ArrayList<ClientData>(group.getClientDataMap().values()); Collections.sort(clientDataList, new Comparator<ClientData>() { @Override @@ -41,16 +60,10 @@ } }); for (ClientData data : clientDataList) { - clientTokens.add(String.format("%s, %s", data, data.getTotalTokens())); - totalConsumedGroupTokens += data.getTotalTokens(); + writer.println(String.format("%s, %s, %s, %s, %s", data, group, data.getTotalTokens(), data.getSanctionCosts(), data.getSanctionPenalties())); + totalTokensHarvested += data.getTotalTokens(); } - writer.println( - String.format("%s, %s, %s, %s", - group, - Utils.join(',', clientTokens), - group.getResourceDistributionSize(), - totalConsumedGroupTokens) - ); + writer.println(String.format("Group %s, %s, %s", group, group.getResourceDistributionSize(), totalTokensHarvested)); } Map<GroupDataModel, SortedSet<ChatRequest>> chatRequestMap = new HashMap<GroupDataModel, SortedSet<ChatRequest>>(); SortedSet<ChatRequest> allChatRequests = savedRoundData.getChatRequests(); @@ -77,8 +90,50 @@ } } } - + writer.println("========================================="); + writer.println("Time, Participant, Token Collected?, Chat"); + Map<Identifier, RuleVoteRequest> ruleVoteRequests = new HashMap<Identifier, RuleVoteRequest>(); + ArrayList<RuleSelectedUpdateEvent> ruleSelectedEvents = new ArrayList<RuleSelectedUpdateEvent>(); + for (PersistableEvent action: savedRoundData.getActions()) { + if (action instanceof ChatRequest) { + writer.println(String.format("%s, %s, %s, %s", + savedRoundData.toSecondString(action), action.getId(), 0, action.toString())); + } + else if (action instanceof TokenCollectedEvent) { + writer.println(String.format("%s, %s, %s", + savedRoundData.toSecondString(action), action.getId(), "token collected")); + } + else if (action instanceof RuleVoteRequest) { + ruleVoteRequests.put(action.getId(), (RuleVoteRequest) action); + } + else if (action instanceof RuleSelectedUpdateEvent) { + ruleSelectedEvents.add((RuleSelectedUpdateEvent) action); + } + } + if (! ruleVoteRequests.isEmpty()) { + writer.println("=== Selected rules ==="); + for (RuleSelectedUpdateEvent event: ruleSelectedEvents) { + writer.println(event.toString()); + } + for (GroupDataModel group: groups) { + ArrayList<ClientData> clientDataList = new ArrayList<ClientData>(group.getClientDataMap().values()); + Collections.sort(clientDataList, new Comparator<ClientData>() { + @Override + public int compare(ClientData a, ClientData b) { + return Integer.valueOf(a.getAssignedNumber()).compareTo(b.getAssignedNumber()); + } + }); + + writer.println("=== Voting results for " + group.toString() + "==="); + for (ClientData data: clientDataList) { + RuleVoteRequest request = ruleVoteRequests.get(data.getId()); + writer.println(String.format("%s, %s", data.getId(), request.getRule())); + } + + } + } } + @Override public String getOutputFileExtension() { return "-summary.txt"; diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/model/ClientData.java --- a/src/main/java/edu/asu/commons/foraging/model/ClientData.java +++ b/src/main/java/edu/asu/commons/foraging/model/ClientData.java @@ -335,6 +335,15 @@ public int getSanctionPenalties() { return sanctionPenalties; } + + public void addSanctionCosts(int cost) { + sanctionCosts += cost; + } + + public void addSanctionPenalties(int penalty) { + sanctionPenalties += penalty; + } + public int getSanctionCosts() { return sanctionCosts; diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/model/ServerDataModel.java --- a/src/main/java/edu/asu/commons/foraging/model/ServerDataModel.java +++ b/src/main/java/edu/asu/commons/foraging/model/ServerDataModel.java @@ -253,7 +253,7 @@ return new ArrayList<GroupDataModel>(new TreeSet<GroupDataModel>(clientsToGroups.values())); } - protected ClientData getClientData(Identifier id) { + public ClientData getClientData(Identifier id) { return getGroup(id).getClientData(id); } diff -r 91a29135b11f07eaaa4cfc8dc86fc781795d2182 -r 9a85c86b5535bbce0764dcb500812e2475989254 src/main/java/edu/asu/commons/foraging/ui/TrustGamePanel.form --- a/src/main/java/edu/asu/commons/foraging/ui/TrustGamePanel.form +++ b/src/main/java/edu/asu/commons/foraging/ui/TrustGamePanel.form @@ -264,7 +264,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="0 cents"/> + <Property name="text" type="java.lang.String" value="0"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -278,7 +278,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="1 dollar"/> + <Property name="text" type="java.lang.String" value="1"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -292,7 +292,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="(3 x 1) = 3 dollars"/> + <Property name="text" type="java.lang.String" value="(3 x 1) = 3"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -307,7 +307,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="(3 x 0.75) = 2.25 dollars"/> + <Property name="text" type="java.lang.String" value="(3 x 0.75) = 2.25"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -322,7 +322,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="75 cents"/> + <Property name="text" type="java.lang.String" value="0.75"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -336,7 +336,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="25 cents"/> + <Property name="text" type="java.lang.String" value="0.25"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -366,7 +366,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="50 cents"/> + <Property name="text" type="java.lang.String" value="0.50"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -380,7 +380,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="50 cents"/> + <Property name="text" type="java.lang.String" value="0.50"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -394,7 +394,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="(3 x 0.5) = 1.5 dollars"/> + <Property name="text" type="java.lang.String" value="(3 x 0.5) = 1.5"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -417,7 +417,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="75 cents"/> + <Property name="text" type="java.lang.String" value="0.75"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -431,7 +431,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="25 cents"/> + <Property name="text" type="java.lang.String" value="0.25"/><Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"><Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"><LineBorder/> @@ -445,7 +445,7 @@ <Font name="Tahoma" size="14" style="0"/></Property><Property name="horizontalAlignment" type="int" value="0"/> - <Property name="text" type="java.lang.String" value="(3 x 0.25) = 0.75 cents"/> + <Property name="text" type="java.lang.String" value="(3 x 0.25) = 0.75"/><Property name="border" type="javax.swing.border.Bo... [truncated message content] |
From: <com...@bi...> - 2013-03-27 22:54:21
|
1 new commit in foraging: https://bitbucket.org/virtualcommons/foraging/commits/4aeac0166573/ Changeset: 4aeac0166573 User: alllee Date: 2013-03-27 23:53:28 Summary: fixes issue 38 Affected #: 1 file diff -r db5527c3847e68abcccf1619fe6611dda5b696ed -r 4aeac01665735e7d2c07775fb9139394218a2394 build.xml --- a/build.xml +++ b/build.xml @@ -202,7 +202,7 @@ </target><!-- Compile project source files --><target name="compile" depends="prepare, resolve"> - <javac srcdir="${src.dir}" destdir="${build.dir}" debug="on" optimize="off" deprecation="on" source="1.6" includeAntRuntime="false"> + <javac srcdir="${src.dir}" destdir="${build.dir}" debug="on" optimize="off" deprecation="on" source="1.6" target="1.6" includeAntRuntime="false"><compilerarg value="-Xlint:unchecked"/><classpath refid="project.classpath"/></javac> @@ -260,7 +260,7 @@ </target><!-- Compile Tests --><target name="compile-tests" depends="compile"> - <javac srcdir="${test.src.dir}" destdir="${test.build.dir}" source="1.6" debug="on"> + <javac srcdir="${test.src.dir}" destdir="${test.build.dir}" source="1.6" target="1.6" debug="on"><!-- <compilerarg value='-Xlint:unchecked'/> --><classpath refid="project.classpath"/></javac> Repository URL: https://bitbucket.org/virtualcommons/foraging/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-27 22:54:11
|
1 new commit in irrigation: https://bitbucket.org/virtualcommons/irrigation/commits/46ab6623575d/ Changeset: 46ab6623575d User: alllee Date: 2013-03-27 23:53:55 Summary: setting explicit compilation target Affected #: 1 file diff -r 87f79cd356df33c02f7a32183f3789c3e974ad16 -r 46ab6623575d00e9f80a101c6c773a535a999f0a build.xml --- a/build.xml +++ b/build.xml @@ -241,6 +241,7 @@ deprecation="on" includeantruntime='true' source="1.6" + target="1.6" ><compilerarg value='-Xlint:unchecked'/><classpath refid="project.classpath" /> @@ -316,6 +317,7 @@ <javac srcdir="${test.src.dir}" destdir="${test.build.dir}" source="1.6" + target="1.6" debug="on"><!-- <compilerarg value='-Xlint:unchecked'/> --><classpath refid="project.classpath" /> Repository URL: https://bitbucket.org/virtualcommons/irrigation/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: A L. <iss...@bi...> - 2013-03-27 20:16:11
|
New issue 96: boundaries: refresh bug after submitting a decision https://bitbucket.org/virtualcommons/vcweb/issue/96/boundaries-refresh-bug-after-submitting-a A Lee: There's some weirdness with the KO value binding. After submitting a harvest decision and refreshing, the "You have submitted a decision" message loses its value, possibly because the form input is disabled? Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-03-26 20:24:54
|
New issue 95: refactor data value and parameter value API https://bitbucket.org/virtualcommons/vcweb/issue/95/refactor-data-value-and-parameter-value A Lee: set_data_value / get_data_value and get_parameter_value / set_parameter_value are sprinkled all over the various Model classes that have associated data values. Might be able to clean it up by creating a mixin / helper class and composing it into each class. Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-03-21 00:15:02
|
--- you can reply above this line --- New issue 94: improve experimenter UI https://bitbucket.org/virtualcommons/vcweb/issue/94/improve-experimenter-ui A Lee: The experimenter dashboard and experiment monitoring pages (see attachments) could both use some UI refinement. Responsible: smanney -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-03-20 22:44:02
|
--- you can reply above this line --- New issue 93: refactor experimenter dashboard UI https://bitbucket.org/virtualcommons/vcweb/issue/93/refactor-experimenter-dashboard-ui A Lee: Switch to Knockout and change degenerate stateful GET requests into ajax POSTs Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: The V. C. <iss...@bi...> - 2013-03-17 06:34:46
|
--- you can reply above this line --- New issue 92: add repeating round type https://bitbucket.org/virtualcommons/vcweb/issue/92/add-repeating-round-type The Virtual Commons: Experiments with multiple rounds would benefit from a repeating round type or repeat field so we don't have to duplicate the round configuration over and over when there are 10-20 rounds with the same conditions. Implementing this has implications on sequence number however, might be better to replace sequence number round sequencing with linked list style where each round refers to the next one.. Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-03-04 23:00:26
|
--- you can reply above this line --- New issue 91: add experiment completed badge https://bitbucket.org/virtualcommons/vcweb/issue/91/add-experiment-completed-badge A Lee: Shelby, can you provide me an image (png would be fine) for the experiment completed visualization just like the rank1/rank2/rank3 files? http://clients.fervorcreative.com/Clients/ASU/csid/r5/dashboard-experimentcompleted.html Thanks! Responsible: smanney -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-03-02 18:19:41
|
--- you can reply above this line --- New issue 90: prevent sockjs tornado process from using same logfiles as django process https://bitbucket.org/virtualcommons/vcweb/issue/90/prevent-sockjs-tornado-process-from-using A Lee: logging config is being duplicated Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-02-28 19:28:19
|
--- you can reply above this line --- New issue 89: fix json serialization / deserialization https://bitbucket.org/virtualcommons/vcweb/issue/89/fix-json-serialization-deserialization A Lee: Django 1.5 deprecated django.utils.simplejson for good reasons https://code.djangoproject.com/ticket/18023 Need to fix vcweb.core.json to reflect this Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-02-23 07:36:41
|
--- you can reply above this line --- New issue 88: redesign experimenter dashboard UI https://bitbucket.org/virtualcommons/vcweb/issue/88/redesign-experimenter-dashboard-ui A Lee: experimenter dashboard is cluttered and hard to navigate when there are a lot of experiments. Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-02-22 07:24:44
|
--- you can reply above this line --- New issue 87: verify & create custom email for class pretest registration https://bitbucket.org/virtualcommons/vcweb/issue/87/verify-create-custom-email-for-class A Lee: Subject: ASB 328: Experiment for extra credit Hello, Thanks in advance for participating in this experiment pretest. You have been randomly allocated to a group of 5, along with four other students who are also in ASB 328. You can earn extra credit points for the course by reducing your virtual carbon footprint. To access the game you need to go to LINK, and login with EMAILADDRESS and password: test The experiment runs from Monday February 25 till March 1. There are three levels in this game, and to move to the next level your group needs to reach an average carbon footprint savings of a certain amount of points. When your group reaches another level new options become available. The following is the payoff in terms of extra credit points: Finished level 3 on Wednesday 10 points for each group member Finished level 3 on Thursday 8 points for each group member Finished level 3 on Friday 6 points for each group member Finished level 2 on Friday 4 points for each group member Finished level 1 on Friday 2 points for each group member Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-02-22 00:07:38
|
--- you can reply above this line --- New issue 86: replace simplecache with django cache framework https://bitbucket.org/virtualcommons/vcweb/issue/86/replace-simplecache-with-django-cache A Lee: Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-02-21 22:31:38
|
--- you can reply above this line --- New issue 85: boundaries: switch from tab instructions to templated instructions https://bitbucket.org/virtualcommons/vcweb/issue/85/boundaries-switch-from-tab-instructions-to A Lee: introduce a new ko observable templateName Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-02-21 22:30:51
|
--- you can reply above this line --- New issue 84: lighter footprints: completion of the experiment https://bitbucket.org/virtualcommons/vcweb/issue/84/lighter-footprints-completion-of-the A Lee: After reaching completing level 3: * no more summary emails * some kind of visual image / text denoting that they've finished the experiment. Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: A L. <iss...@bi...> - 2013-02-21 22:29:42
|
--- you can reply above this line --- New issue 83: lighter footprints: add data value parameter for completion https://bitbucket.org/virtualcommons/vcweb/issue/83/lighter-footprints-add-data-value A Lee: need a group round data value "completed" that signifies they've finished level 3. Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |