virtualcommons-svn Mailing List for Virtual Commons Experiment Software (Page 45)
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: <vir...@li...> - 2010-09-08 21:44:24
|
Subject: hg.virtualcommons 49 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/921f34adf8d2 changeset: 49:921f34adf8d2 user: alllee date: Wed Sep 08 14:44:17 2010 -0700 description: adding additional test fixtures for test users, participants, and starting to flesh out forestry configuration diffstat: vcweb/core/fixtures/test_users_participants.json | 308 +++++++++++++++++++++++ vcweb/forestry/fixtures/forestry_test_data.json | 102 +++++++ vcweb/forestry/fixtures/initial_data.json | 34 ++ 3 files changed, 444 insertions(+), 0 deletions(-) diffs (461 lines): diff -r ab5177b83b36 -r 921f34adf8d2 vcweb/core/fixtures/test_users_participants.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/fixtures/test_users_participants.json Wed Sep 08 14:44:17 2010 -0700 @@ -0,0 +1,308 @@ +[ + { + "pk": 1, + "model": "sites.site", + "fields": { + "domain": "example.com", + "name": "example.com" + } + }, + { + "pk": 1, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 2, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 2, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 3, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 3, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 4, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 4, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 5, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 5, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 6, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 6, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 7, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 7, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 8, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 8, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 9, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 9, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 10, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 10, + "model": "core.participant", + "fields": { + "can_receive_invitations": true, + "user": 11, + "failed_password_attempts": 0, + "institution": 1 + } + }, + { + "pk": 2, + "model": "auth.user", + "fields": { + "username": "testuser1", + "first_name": "User 1", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 13:12:26", + "groups": [ + 2 + ], + "user_permissions": [], + "password": "sha1$54737$7593e4e8c52c0ca5b763a08cc418e171d9b01ea2", + "email": "tu...@ex...", + "date_joined": "2010-09-07 13:12:26" + } + }, + { + "pk": 3, + "model": "auth.user", + "fields": { + "username": "testuser2", + "first_name": "User 2", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 13:13:01", + "groups": [ + 2 + ], + "user_permissions": [], + "password": "sha1$30244$03c8242e416d74be6048305e4a9a33ee9a533d49", + "email": "tu...@ex...", + "date_joined": "2010-09-07 13:13:01" + } + }, + { + "pk": 4, + "model": "auth.user", + "fields": { + "username": "testuser3", + "first_name": "User 3", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 13:13:24", + "groups": [ + 2 + ], + "user_permissions": [], + "password": "sha1$c2ef6$85466c9f4e4f0bbe146a9f22c976f294af509ae4", + "email": "tu...@ex...", + "date_joined": "2010-09-07 13:13:24" + } + }, + { + "pk": 5, + "model": "auth.user", + "fields": { + "username": "testuser4", + "first_name": "User 4", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 13:13:47", + "groups": [ + 2 + ], + "user_permissions": [], + "password": "sha1$3b7ec$6fbcf8a00bae1ac2343254c0c241e50dfe5596e5", + "email": "tu...@ex...", + "date_joined": "2010-09-07 13:13:47" + } + }, + { + "pk": 6, + "model": "auth.user", + "fields": { + "username": "testuser5", + "first_name": "User 5", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 13:15:29", + "groups": [ + 2 + ], + "user_permissions": [], + "password": "sha1$45403$2cbe8d4f3da7b3132d7fab9ca76cbefae20180f7", + "email": "tu...@ex...", + "date_joined": "2010-09-07 13:15:29" + } + }, + { + "pk": 7, + "model": "auth.user", + "fields": { + "username": "testuser6", + "first_name": "User 6", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 13:17:43", + "groups": [ + 2 + ], + "user_permissions": [], + "password": "sha1$e5386$dec49fcee74ef2e11e8e2ed50bf43cd07adac666", + "email": "tu...@ex...", + "date_joined": "2010-09-07 13:17:43" + } + }, + { + "pk": 8, + "model": "auth.user", + "fields": { + "username": "testuser7", + "first_name": "User 7", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 13:18:31", + "groups": [], + "user_permissions": [], + "password": "sha1$f7afe$87817e7608c5a1b67465f94428f3ae3ddc108268", + "email": "tu...@ex...", + "date_joined": "2010-09-07 13:18:31" + } + }, + { + "pk": 9, + "model": "auth.user", + "fields": { + "username": "testuser8", + "first_name": "User 8", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 14:46:18", + "groups": [ + 2 + ], + "user_permissions": [], + "password": "sha1$9b0c6$9316e579e772623599c47a82cc31eb5935d8b162", + "email": "tu...@ex...", + "date_joined": "2010-09-07 14:46:18" + } + }, + { + "pk": 10, + "model": "auth.user", + "fields": { + "username": "testuser9", + "first_name": "User 9", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 14:46:35", + "groups": [ + 2 + ], + "user_permissions": [], + "password": "sha1$eefd8$d627da000b244e7355316a72b90c865074d70275", + "email": "tu...@ex...", + "date_joined": "2010-09-07 14:46:35" + } + }, + { + "pk": 11, + "model": "auth.user", + "fields": { + "username": "testuser10", + "first_name": "User 10", + "last_name": "Test", + "is_active": true, + "is_superuser": false, + "is_staff": false, + "last_login": "2010-09-07 14:46:52", + "groups": [ + 2 + ], + "user_permissions": [], + "password": "sha1$589d0$b4b5dd05c61ddb9931d26dfe5737560f59f609e9", + "email": "tu...@ex...", + "date_joined": "2010-09-07 14:46:52" + } + } +] diff -r ab5177b83b36 -r 921f34adf8d2 vcweb/forestry/fixtures/forestry_test_data.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/forestry/fixtures/forestry_test_data.json Wed Sep 08 14:44:17 2010 -0700 @@ -0,0 +1,102 @@ +[ + { + "pk": 1, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:08:55", + "experiment": 1, + "participant": 1, + "created_by": 1 + } + }, + { + "pk": 2, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:09:05", + "experiment": 1, + "participant": 2, + "created_by": 1 + } + }, + { + "pk": 3, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:09:13", + "experiment": 1, + "participant": 3, + "created_by": 1 + } + }, + { + "pk": 4, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:09:20", + "experiment": 1, + "participant": 4, + "created_by": 1 + } + }, + { + "pk": 5, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:09:25", + "experiment": 1, + "participant": 5, + "created_by": 1 + } + }, + { + "pk": 6, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:09:31", + "experiment": 1, + "participant": 6, + "created_by": 1 + } + }, + { + "pk": 7, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:09:36", + "experiment": 1, + "participant": 7, + "created_by": 1 + } + }, + { + "pk": 8, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:09:40", + "experiment": 1, + "participant": 8, + "created_by": 1 + } + }, + { + "pk": 9, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:09:45", + "experiment": 1, + "participant": 9, + "created_by": 1 + } + }, + { + "pk": 10, + "model": "core.participantexperimentrelationship", + "fields": { + "date_created": "2010-09-07 15:09:55", + "experiment": 1, + "participant": 10, + "created_by": 1 + } + } +] diff -r ab5177b83b36 -r 921f34adf8d2 vcweb/forestry/fixtures/initial_data.json --- a/vcweb/forestry/fixtures/initial_data.json Tue Sep 07 17:12:21 2010 -0700 +++ b/vcweb/forestry/fixtures/initial_data.json Wed Sep 08 14:44:17 2010 -0700 @@ -19,5 +19,39 @@ "experiment_metadata": ["forestry"], "is_public": true } + }, + { + "pk": 1, + "model": "core.experiment", + "fields": { + "experiment_metadata": 1, + "status": "INACTIVE", + "start_date_time": null, + "current_round_elapsed_time": 0, + "tick_duration": "10s", + "current_round_number": 1, + "authentication_code": "TEST_FORESTRY", + "total_elapsed_time": 0, + "last_modified": "2010-09-07 15:10:37", + "experimenter": 1, + "duration": "1h", + "date_created": "2010-09-07 13:10:47", + "experiment_configuration": 1, + "is_experimenter_driven": true + } + }, + { + "pk": 1, + "model": "core.roundconfiguration", + "fields": { + "round_type": "INSTRUCTIONS", + "debriefing": "Initial debriefing for the forestry experiment.", + "last_modified": "2010-09-07 15:13:03", + "duration": 0, + "date_created": "2010-09-07 15:13:03", + "experiment_configuration": 1, + "sequence_number": 1, + "instructions": "Initial instructions for the forestry experiment." + } } ] |
From: <vir...@li...> - 2010-09-08 02:44:20
|
Subject: hg.virtualcommons 48 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/ab5177b83b36 changeset: 48:ab5177b83b36 user: alllee date: Tue Sep 07 17:12:21 2010 -0700 description: updating core data models: - adding is_required to ConfigurationParameter - updating many-to-many fields related_names for experiments <-> participants so you can refer to experiment.participants and participant.experiments - starting to set up methods on Experiment to start an experiment, allocate groups, etc. diffstat: vcweb/core/admin.py | 1 + vcweb/core/models.py | 30 +++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diffs (96 lines): diff -r 26f9b965c4cf -r ab5177b83b36 vcweb/core/admin.py --- a/vcweb/core/admin.py Fri Sep 03 15:14:56 2010 -0700 +++ b/vcweb/core/admin.py Tue Sep 07 17:12:21 2010 -0700 @@ -7,6 +7,7 @@ admin.site.register(DataParameter) admin.site.register(RoundParameter) +admin.site.register(ConfigurationParameter) admin.site.register(ExperimentConfiguration) admin.site.register(RoundConfiguration) admin.site.register(Experimenter) diff -r 26f9b965c4cf -r ab5177b83b36 vcweb/core/models.py --- a/vcweb/core/models.py Fri Sep 03 15:14:56 2010 -0700 +++ b/vcweb/core/models.py Tue Sep 07 17:12:21 2010 -0700 @@ -351,7 +351,7 @@ is_public = models.BooleanField(default=True) def __unicode__(self): - return "Experiment Configuration [{name}] for {experiment_metadata} created by {creator} on {date_created}".format(name=self.name, + return "Experiment configuration [{name}] for {experiment_metadata} created by {creator} on {date_created}".format(name=self.name, experiment_metadata=self.experiment_metadata, creator=self.creator, date_created=self.date_created) @@ -404,6 +404,23 @@ objects = ExperimentManager() + def start(self): + if self.is_started(): + self.allocate_groups() + self.status = 'ACTIVE' + self.save() + + + def allocate_groups(self, randomize=True): + logger.debug("allocating groups from all participants: %s" % self.participants) + + + + + def is_started(self): + return self.status != 'INACTIVE' + + def advance_to_next_round(self): self.current_round_elapsed_time = 0 self.current_round_number += 1 @@ -460,11 +477,11 @@ class RoundConfiguration(models.Model): ROUND_TYPE_CHOICES = ( - ('INSTRUCTIONS', 'Instructions'), + ('INSTRUCTIONS', 'Instructions round'), ('QUIZ', 'Quiz round'), ('CHAT', 'Chat round'), ('PRACTICE', 'Practice round'), - ('PLAY', 'Actual experiment_metadata round'), + ('PLAY', 'Actual experiment round'), ) experiment_configuration = models.ForeignKey(ExperimentConfiguration) sequence_number = models.PositiveIntegerField() @@ -524,6 +541,7 @@ last_modified = models.DateTimeField(auto_now=True) creator = models.ForeignKey(Experimenter) + def __unicode__(self): return "{0} ({1})".format(self.name, self.type) @@ -535,6 +553,7 @@ Configuration parameters are used to tune the """ class ConfigurationParameter(Parameter): + is_required = models.BooleanField(default=False) def __unicode__(self): return 'Configuration Parameter: ' + self.name @@ -607,7 +626,7 @@ experiment = models.ForeignKey(Experiment) def __unicode__(self): - return "Data value: parameter {0}, value {1}, time recorded {2}, experiment_metadata {3}".format(self.parameter, self.parameter_value, self.time_recorded, self.experiment) + return "Data value: [parameter {0}, value {1}], recorded at {2} for experiment {3}".format(self.parameter, self.parameter_value, self.time_recorded, self.experiment) class Meta: abstract = True @@ -619,7 +638,8 @@ class Participant(CommonsUser): can_receive_invitations = models.BooleanField(default=False) - group = models.ManyToManyField(Group, through='ParticipantGroupRelationship', related_name='groups') + groups = models.ManyToManyField(Group, through='ParticipantGroupRelationship', related_name='participants') + experiments = models.ManyToManyField(Experiment, through='ParticipantExperimentRelationship', related_name='participants') # objects = ParticipantManager() class Meta: ordering = ['user'] |
From: <vir...@li...> - 2010-09-03 22:15:06
|
Subject: hg.virtualcommons 47 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/26f9b965c4cf changeset: 47:26f9b965c4cf user: alllee date: Fri Sep 03 15:14:56 2010 -0700 description: fixing admin model references diffstat: vcweb/core/admin.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diffs (20 lines): diff -r 0d99df22d584 -r 26f9b965c4cf vcweb/core/admin.py --- a/vcweb/core/admin.py Fri Sep 03 14:53:06 2010 -0700 +++ b/vcweb/core/admin.py Fri Sep 03 15:14:56 2010 -0700 @@ -3,8 +3,7 @@ ''' from django.contrib import admin -from vcweb.core.models import DataParameter, RoundParameter, ExperimentConfiguration, \ - RoundConfiguration, Experimenter, Participant, Experiment, ParticipantGroup, Group +from vcweb.core.models import * admin.site.register(DataParameter) admin.site.register(RoundParameter) @@ -14,4 +13,5 @@ admin.site.register(Participant) admin.site.register(Group) admin.site.register(Experiment) -admin.site.register(ParticipantGroup) +admin.site.register(ParticipantExperimentRelationship) +admin.site.register(ParticipantGroupRelationship) |
From: <vir...@li...> - 2010-09-03 21:53:13
|
Subject: hg.virtualcommons 46 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/0d99df22d584 changeset: 46:0d99df22d584 user: alllee date: Fri Sep 03 14:53:06 2010 -0700 description: adding ParticipantExperimentRelationship entity to capture participants that are part of an experiment but not yet assigned to groups (modeled in ParticipantGroupRelationship) diffstat: vcweb/core/models.py | 26 +++++++++++++++++++++----- 1 files changed, 21 insertions(+), 5 deletions(-) diffs (57 lines): diff -r eb86acb58090 -r 0d99df22d584 vcweb/core/models.py --- a/vcweb/core/models.py Fri Sep 03 13:23:13 2010 -0700 +++ b/vcweb/core/models.py Fri Sep 03 14:53:06 2010 -0700 @@ -330,7 +330,7 @@ return self.user.is_authenticated() def __unicode__(self): - return "{0} ({1})".format(self.user.get_full_name(), self.user.username) + return "{0} ({1})".format(self.user.get_full_name(), self.user.email) class Meta: abstract = True @@ -351,7 +351,10 @@ is_public = models.BooleanField(default=True) def __unicode__(self): - return "Experiment Configuration [{name}] for {experiment_metadata} created by {creator} on {date_created}".format(name=self.name, experiment_metadata=self.experiment_metadata, creator=self.creator, date_created=self.date_created) + return "Experiment Configuration [{name}] for {experiment_metadata} created by {creator} on {date_created}".format(name=self.name, + experiment_metadata=self.experiment_metadata, + creator=self.creator, + date_created=self.date_created) class Meta: ordering = ['experiment_metadata', 'creator', 'date_created'] @@ -616,16 +619,29 @@ class Participant(CommonsUser): can_receive_invitations = models.BooleanField(default=False) - group = models.ManyToManyField(Group, through='ParticipantGroup', related_name='groups') + group = models.ManyToManyField(Group, through='ParticipantGroupRelationship', related_name='groups') # objects = ParticipantManager() class Meta: ordering = ['user'] """ +Many-to-many relationship entity storing a participant and the experiment they are participating in. +""" +class ParticipantExperimentRelationship(models.Model): + participant = models.ForeignKey(Participant) + experiment = models.ForeignKey(Experiment) + date_created = models.DateTimeField(auto_now_add=True) + created_by = models.ForeignKey(User) + + def __unicode__(self): + return "Experiment {0} - participant {1} (created {2})".format(self.experiment, self.participant, self.date_created) + + +""" Many-to-many relationship entity storing a participant, group, their participant number in that group, the -round in which +round in which they joined the group, and the datetime that they joined the group. """ -class ParticipantGroup(models.Model): +class ParticipantGroupRelationship(models.Model): participant_number = models.PositiveIntegerField() participant = models.ForeignKey(Participant) group = models.ForeignKey(Group) |
From: <vir...@li...> - 2010-09-03 20:23:21
|
Subject: hg.virtualcommons 45 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/eb86acb58090 changeset: 45:eb86acb58090 user: alllee date: Fri Sep 03 13:23:13 2010 -0700 description: model renaming diffstat: vcweb/core/admin.py | 13 +- vcweb/core/auth.py | 3 +- vcweb/core/models.py | 74 +++++++++--------- vcweb/core/signals.py | 6 +- vcweb/core/tasks.py | 2 +- vcweb/core/templates/includes/participant-nav-menu.inc | 4 +- vcweb/core/templates/participant-index.html | 17 ++- vcweb/core/urls.py | 2 +- vcweb/core/views.py | 8 +- vcweb/forestry/fixtures/initial_data.json | 6 +- vcweb/forestry/models.py | 4 +- vcweb/forestry/templates/forestry/index.html | 19 +-- vcweb/forestry/urls.py | 4 +- vcweb/forestry/views.py | 27 +++-- 14 files changed, 97 insertions(+), 92 deletions(-) diffs (519 lines): diff -r 5ba301382f1a -r eb86acb58090 vcweb/core/admin.py --- a/vcweb/core/admin.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/core/admin.py Fri Sep 03 13:23:13 2010 -0700 @@ -1,20 +1,17 @@ ''' -Created on Jul 8, 2010 - -@author: alllee +registering django models with django admin ''' -from Canvas import Group from django.contrib import admin -from vcweb.core.models import DataParameter, RoundParameter, GameConfiguration, \ - RoundConfiguration, Experimenter, Participant, GameInstance, ParticipantGroup +from vcweb.core.models import DataParameter, RoundParameter, ExperimentConfiguration, \ + RoundConfiguration, Experimenter, Participant, Experiment, ParticipantGroup, Group admin.site.register(DataParameter) admin.site.register(RoundParameter) -admin.site.register(GameConfiguration) +admin.site.register(ExperimentConfiguration) admin.site.register(RoundConfiguration) admin.site.register(Experimenter) admin.site.register(Participant) admin.site.register(Group) -admin.site.register(GameInstance) +admin.site.register(Experiment) admin.site.register(ParticipantGroup) diff -r 5ba301382f1a -r eb86acb58090 vcweb/core/auth.py --- a/vcweb/core/auth.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/core/auth.py Fri Sep 03 13:23:13 2010 -0700 @@ -17,15 +17,14 @@ logger = logging.getLogger('vcweb.core.auth') +# FIXME: check for and handle Participant experiment auth codes. class AuthenticationBackend(ModelBackend): def authenticate(self, username=None, password=None): if email_re.search(username): try: user = User.objects.get(email=username) - # FIXME: check for Participant game codes. if user.check_password(password): return user - # password may be game code. check it against participant's game game codes. except User.DoesNotExist: return None return None diff -r 5ba301382f1a -r eb86acb58090 vcweb/core/models.py --- a/vcweb/core/models.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/core/models.py Fri Sep 03 13:23:13 2010 -0700 @@ -23,11 +23,11 @@ """ def second_tick_handler(sender, time=None, **kwargs): logger.debug("handling second tick signal at %s" % time) - # inspect all active games and update their time left - for gameInstance in GameInstance.objects.filter(status='ROUND_IN_PROGRESS'): - # how to invoke a game-type-specific handler here? - gameInstance.increment_elapsed_time() - gameInstance.save() + # inspect all active experiments and update their time left + for experiment in Experiment.objects.filter(status='ROUND_IN_PROGRESS'): + # how to invoke a experiment_metadata-type-specific handler here? + experiment.increment_elapsed_time() + experiment.save() signals.second_tick.connect(second_tick_handler, sender=None) @@ -274,25 +274,25 @@ self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL) # manager classes -class GameMetadataManager(models.Manager): +class ExperimentMetadataManager(models.Manager): def get_by_natural_key(self, key): return self.get(namespace=key) # Create your models here. -class GameMetadata(models.Model): +class ExperimentMetadata(models.Model): title = models.CharField(max_length=255) - # the URL namespace that this game will occupy + # the URL namespace that this experiment_metadata will occupy namespace = models.CharField(max_length=255, unique=True, validators=[RegexValidator(regex=r'^\w+$'), ]) description = models.TextField(null=True, blank=True) date_created = models.DateField(auto_now_add=True) last_modified = models.DateTimeField(auto_now=True) about_url = models.URLField(null=True, blank=True, verify_exists=True) logo_url = models.URLField(null=True, blank=True, verify_exists=True) - default_game_configuration = models.ForeignKey('GameConfiguration', null=True, blank=True) + default_configuration = models.ForeignKey('ExperimentConfiguration', null=True, blank=True) - objects = GameMetadataManager() + objects = ExperimentMetadataManager() def natural_key(self): return [self.namespace] @@ -341,8 +341,8 @@ class Meta: ordering = ['user'] -class GameConfiguration(models.Model): - game = models.ForeignKey(GameMetadata) +class ExperimentConfiguration(models.Model): + experiment_metadata = models.ForeignKey(ExperimentMetadata) creator = models.ForeignKey(Experimenter) name = models.CharField(max_length=255) maximum_number_of_participants = models.PositiveIntegerField() @@ -351,21 +351,21 @@ is_public = models.BooleanField(default=True) def __unicode__(self): - return "{name} (GameConfiguration) for {game} created by {creator} on {date_created}".format(name=self.name, game=self.game, creator=self.creator, date_created=self.date_created) + return "Experiment Configuration [{name}] for {experiment_metadata} created by {creator} on {date_created}".format(name=self.name, experiment_metadata=self.experiment_metadata, creator=self.creator, date_created=self.date_created) class Meta: - ordering = ['game', 'creator', 'date_created'] + ordering = ['experiment_metadata', 'creator', 'date_created'] -class GameInstanceManager(models.Manager): +class ExperimentManager(models.Manager): def get_all_active(self): return self.filter(status='ACTIVE') -# an actual instance of a game; represents a concrete -# parameterization of this game. -class GameInstance(models.Model): - GAME_STATUS_CHOICES = ( +# an actual instance of an experiment; represents a concrete +# parameterization of this experiment. +class Experiment(models.Model): + STATUS_CHOICES = ( ('INACTIVE', 'Not active'), ('ACTIVE', 'Active'), ('PAUSED', 'Paused'), @@ -377,19 +377,19 @@ authentication_code = models.CharField(max_length=255) current_round_number = models.PositiveIntegerField() experimenter = models.ForeignKey(Experimenter) - game_metadata = models.ForeignKey(GameMetadata) - game_configuration = models.ForeignKey(GameConfiguration) - status = models.CharField(max_length=32, choices=GAME_STATUS_CHOICES) + experiment_metadata = models.ForeignKey(ExperimentMetadata) + experiment_configuration = models.ForeignKey(ExperimentConfiguration) + status = models.CharField(max_length=32, choices=STATUS_CHOICES) date_created = models.DateTimeField(auto_now_add=True) last_modified = models.DateTimeField(auto_now=True) start_date_time = models.DateTimeField(null=True, blank=True) # how long this experiment should run in a date format # 1w2d = 1 week 2 days = 9d duration = models.CharField(max_length=32) - """ how often the game server should tick. """ + """ how often the experiment_metadata server should tick. """ tick_duration = models.CharField(max_length=32) - """ total elapsed time in seconds since this game was started, incremented by the heartbeat monitor. """ + """ total elapsed time in seconds since this experiment_metadata was started, incremented by the heartbeat monitor. """ total_elapsed_time = models.PositiveIntegerField(default=0) """ elapsed time in seconds for the current round. """ current_round_elapsed_time = models.PositiveIntegerField(default=0) @@ -399,7 +399,7 @@ """ is_experimenter_driven = models.BooleanField(default=True) - objects = GameInstanceManager() + objects = ExperimentManager() def advance_to_next_round(self): self.current_round_elapsed_time = 0 @@ -416,7 +416,7 @@ @property def get_current_round(self): - return RoundConfiguration.objects.get(game_configuration=self.game_configuration, sequence_number=self.current_round_number) + return RoundConfiguration.objects.get(experiment_configuration=self.experiment_configuration, sequence_number=self.current_round_number) @property def url(self, request): @@ -437,14 +437,14 @@ @property def namespace(self): - return self.game_metadata.namespace + return self.experiment_metadata.namespace @property def url_id(self): - return "{0}/{1}".format(self.game_metadata.namespace, self.id) + return "{0}/{1}".format(self.experiment_metadata.namespace, self.id) def __unicode__(self): - return "{game} created by {experimenter} on {date_created}: {status}".format(game=self.game_metadata, experimenter=self.experimenter, date_created=self.date_created, status=self.status) + return "{experiment_metadata} created by {experimenter} on {date_created}: {status}".format(experiment_metadata=self.experiment_metadata, experimenter=self.experimenter, date_created=self.date_created, status=self.status) def ___eq___(self, other): return self.id == other.id @@ -461,9 +461,9 @@ ('QUIZ', 'Quiz round'), ('CHAT', 'Chat round'), ('PRACTICE', 'Practice round'), - ('PLAY', 'Actual game round'), + ('PLAY', 'Actual experiment_metadata round'), ) - game_configuration = models.ForeignKey(GameConfiguration) + experiment_configuration = models.ForeignKey(ExperimentConfiguration) sequence_number = models.PositiveIntegerField() date_created = models.DateTimeField(auto_now_add=True) last_modified = models.DateTimeField(auto_now=True) @@ -501,7 +501,7 @@ return None def __unicode__(self): - return "Round # {0} for game {1} ".format(self.sequence_number, self.game_configuration) + return "Round # {0} for experiment_metadata {1} ".format(self.sequence_number, self.experiment_configuration) # class Meta: # db_table = 'vcweb_round_configuration' @@ -569,13 +569,13 @@ class Group(models.Model): number = models.PositiveIntegerField() max_size = models.PositiveIntegerField() - game_instance = models.ForeignKey(GameInstance) + experiment = models.ForeignKey(Experiment) def __unicode__(self): - return "Group #{0} in {1}".format(self.number, self.game_instance) + return "Group #{0} in {1}".format(self.number, self.experiment) class Meta: - ordering = ['game_instance', 'number'] + ordering = ['experiment', 'number'] """ @@ -601,10 +601,10 @@ parameter_value = models.CharField(max_length=512) # FIXME: change to DateTimeField time_recorded = models.DateTimeField(auto_now_add=True) - game_instance = models.ForeignKey(GameInstance) + experiment = models.ForeignKey(Experiment) def __unicode__(self): - return "Data value: parameter {0}, value {1}, time recorded {2}, game {3}".format(self.parameter, self.parameter_value, self.time_recorded, self.game_instance) + return "Data value: parameter {0}, value {1}, time recorded {2}, experiment_metadata {3}".format(self.parameter, self.parameter_value, self.time_recorded, self.experiment) class Meta: abstract = True diff -r 5ba301382f1a -r eb86acb58090 vcweb/core/signals.py --- a/vcweb/core/signals.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/core/signals.py Fri Sep 03 13:23:13 2010 -0700 @@ -7,9 +7,9 @@ from django.dispatch import Signal -game_started = Signal(providing_args=["game_instance_id", "time", "experimenter"]) -round_started = Signal(providing_args=["game_instance_id", 'round_configuration_id']) -round_ended = Signal(providing_args=['game_instance_id', 'round_configuration_id']) +experiment_started = Signal(providing_args=["experiment_id", "time", "experimenter"]) +round_started = Signal(providing_args=["experiment_id", 'round_configuration_id']) +round_ended = Signal(providing_args=['experiment_id', 'round_configuration_id']) second_tick = Signal(providing_args=['time']) post_login = Signal(providing_args=['user']) diff -r 5ba301382f1a -r eb86acb58090 vcweb/core/tasks.py --- a/vcweb/core/tasks.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/core/tasks.py Fri Sep 03 13:23:13 2010 -0700 @@ -12,7 +12,7 @@ @periodic_task(run_every=timedelta(seconds=1), ignore_result=True) def every_second(): - # use signal or just update game instance models directly here? + # use signal or just update experiment instance models directly here? signals.second_tick.send(sender=None, time=datetime.now()) diff -r 5ba301382f1a -r eb86acb58090 vcweb/core/templates/includes/participant-nav-menu.inc --- a/vcweb/core/templates/includes/participant-nav-menu.inc Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/core/templates/includes/participant-nav-menu.inc Fri Sep 03 13:23:13 2010 -0700 @@ -8,8 +8,8 @@ <div id='menu'> <ul> - <li class='{% active request games %}'><a href='{{ games }}'>Your games</a></li> - <li class='{% active request profile %}'><a href='{{ profile }}'>Your account</a> + <li class='{% active request games %}'><a href='{{ games }}'>Dashboard</a></li> + <li class='{% active request profile %}'><a href='{{ profile }}'>Account</a> <li><a href='{{ logout }}'>Logout</a></li> </ul> </div> \ No newline at end of file diff -r 5ba301382f1a -r eb86acb58090 vcweb/core/templates/participant-index.html --- a/vcweb/core/templates/participant-index.html Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/core/templates/participant-index.html Fri Sep 03 13:23:13 2010 -0700 @@ -8,16 +8,23 @@ {% endblock %} {% block content %} <div class='notice'> -Welcome back, {{participant}}. Games you are participating in are listed below. +Welcome back, {{participant}}. Experiments you are currently participating in are listed below. </div> <fieldset> <legend>Your experiments</legend> +{% if games %} <ul> -{% for game_instance in games %} -<li> -<a href='{{game_instance.participant_url}}'>{{ game_instance }}</a></li> -{% endfor %} + {% for game_instance in games %} + <li><a href='{{game_instance.participant_url}}'>{{ + game_instance }}</a></li> + {% endfor %} </ul> +{% else %} +<div class='info'> +You are not participating in any active experiments. +</div> +{% endif %} + </fieldset> {% endblock content %} diff -r 5ba301382f1a -r eb86acb58090 vcweb/core/urls.py --- a/vcweb/core/urls.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/core/urls.py Fri Sep 03 13:23:13 2010 -0700 @@ -11,5 +11,5 @@ url(r'accounts/profile/$', 'account_profile', name='profile'), url(r'experimenter/$', 'experimenter_index', name='experimenter-index'), url(r'participant/$', 'participant_index', name='participant-index'), - url(r'experimenter/configure/(?P<game_instance_id>\d+)$', 'configure', name='configure-experiment'), + url(r'experimenter/configure/(?P<experiment_id>\d+)$', 'configure', name='configure-experiment'), ) diff -r 5ba301382f1a -r eb86acb58090 vcweb/core/views.py --- a/vcweb/core/views.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/core/views.py Fri Sep 03 13:23:13 2010 -0700 @@ -5,7 +5,7 @@ from django.shortcuts import render_to_response, redirect from django.template.context import RequestContext from vcweb.core.forms import RegistrationForm, LoginForm -from vcweb.core.models import Participant, GameInstance, Experimenter +from vcweb.core.models import Participant, Experiment, Experimenter import logging logger = logging.getLogger("core-views") @@ -51,7 +51,7 @@ user = request.user try: experimenter = user.experimenter - games = GameInstance.objects.filter(experimenter=experimenter) + experiments = Experiment.objects.filter(experimenter=experimenter) return render_to_response('experimenter-index.html', RequestContext(request, locals())) except Experimenter.DoesNotExist: return redirect('home') @@ -61,7 +61,7 @@ user = request.user try: participant = user.participant - games = [ group.game_instance for group in participant.group.all() ] + experiments = [ group.experiment for group in participant.group.all() ] return render_to_response('participant-index.html', RequestContext(request, locals())) except Participant.DoesNotExist: # add error message @@ -73,6 +73,6 @@ @login_required -def configure(request, game_instance_id): +def configure(request, experiment_id): # lookup game instance id (or create a new one?) return render_to_response('configure.html', RequestContext(request)) diff -r 5ba301382f1a -r eb86acb58090 vcweb/forestry/fixtures/initial_data.json --- a/vcweb/forestry/fixtures/initial_data.json Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/forestry/fixtures/initial_data.json Fri Sep 03 13:23:13 2010 -0700 @@ -1,7 +1,7 @@ [ { "pk": 1, - "model": "core.gamemetadata", + "model": "core.experimentmetadata", "fields": { "description": "Web-based version of the forestry field experiments.", "title": "Forestry Web Experiment", @@ -11,12 +11,12 @@ }, { "pk": 1, - "model": "core.gameconfiguration", + "model": "core.experimentconfiguration", "fields": { "name": "Forestry Default Configuration", "creator": 1, "maximum_number_of_participants": 20, - "game": ["forestry"], + "experiment_metadata": ["forestry"], "is_public": true } } diff -r 5ba301382f1a -r eb86acb58090 vcweb/forestry/models.py --- a/vcweb/forestry/models.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/forestry/models.py Fri Sep 03 13:23:13 2010 -0700 @@ -7,7 +7,7 @@ def forestry_second_tick(self): - print "Monitoring Forestry Game Instances." + print "Monitoring Forestry Experiments." ''' - check all forestry game instances + check all forestry experiments. ''' diff -r 5ba301382f1a -r eb86acb58090 vcweb/forestry/templates/forestry/index.html --- a/vcweb/forestry/templates/forestry/index.html Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/forestry/templates/forestry/index.html Fri Sep 03 13:23:13 2010 -0700 @@ -3,22 +3,19 @@ {% block title %}Forestry{% endblock %} {% block header %} -<div id='menu'> - <ul> - <li><a href='experimenter/'>Experimenters</a></li> - <li><a href='{% url participate %}'>Participate</a></li> - </ul> -</div> - - +{% include "includes/participant-nav-menu.inc" %} {% endblock header %} {% block content %} <div id='post'> - <h2 class='title'>Forestry</h2> + <h2 class='title'>Forestry Experiment</h2> <div class='entry'> - The forestry experiment. - + Welcome back, {{ user }} + TODO: + <ul> + <li>List current experiments.</li> + <li>List past experiments (?)</li> + </ul> </div> diff -r 5ba301382f1a -r eb86acb58090 vcweb/forestry/urls.py --- a/vcweb/forestry/urls.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/forestry/urls.py Fri Sep 03 13:23:13 2010 -0700 @@ -7,6 +7,6 @@ urlpatterns = patterns('vcweb.forestry.views', url(r'^$', 'index', name='index'), url(r'experimenter/$', 'experimenter', name='experimenter'), - url(r'configure/(?P<game_instance_id>\d+)$', 'configure', name='configure-experiment'), - url(r'participate/(?P<game_instance_id>\d+)', 'participate', name='participate'), + url(r'configure/(?P<experiment_id>\d+)$', 'configure', name='configure-experiment'), + url(r'participate/(?P<experiment_id>\d+)', 'participate', name='participate'), ) diff -r 5ba301382f1a -r eb86acb58090 vcweb/forestry/views.py --- a/vcweb/forestry/views.py Tue Aug 31 16:42:03 2010 -0700 +++ b/vcweb/forestry/views.py Fri Sep 03 13:23:13 2010 -0700 @@ -3,25 +3,30 @@ from django.http import Http404 from django.shortcuts import render_to_response, redirect from django.template.context import RequestContext -from vcweb.core.models import GameInstance +from vcweb.core.models import Experiment, is_participant import logging logger = logging.getLogger('forestry.views') +@login_required def index(request): - return render_to_response('forestry/index.html', RequestContext(request)) + if is_participant(request.user): + return render_to_response('forestry/index.html', RequestContext(request)) + return redirect('experimenter') +@login_required def configure(request): return Http404() +@login_required +def experimenter(request): + return render_to_response('forestry/experimenter.html', RequestContext(request)) -def experimenter(request): - return Http404() @login_required -def participate(request, game_instance_id=None): - if game_instance_id is None: - logger.debug("No game instance id specified, redirecting to forestry index page.") +def participate(request, experiment_id=None): + if experiment_id is None: + logger.debug("No experiment id specified, redirecting to forestry index page.") return redirect('index') try: participant = request.user.participant @@ -29,12 +34,12 @@ logger.debug("No participant available on logged in user %s" % request.user) return redirect('index') try: - game_instance = GameInstance.objects.get(pk=game_instance_id) + experiment = Experiment.objects.get(pk=experiment_id) return render_to_response('forestry/participate.html', - { 'participant': participant, 'game_instance' : game_instance }, + { 'participant': participant, 'experiment' : experiment }, context_instance=RequestContext(request)) - except GameInstance.DoesNotExist: - logger.warning("No game instance for id [%s]" % game_instance_id) + except Experiment.DoesNotExist: + logger.warning("No experiment for id [%s]" % experiment_id) return redirect('index') |
From: <vir...@li...> - 2010-09-03 20:23:21
|
Subject: hg.virtualcommons 44 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/5ba301382f1a changeset: 44:5ba301382f1a user: alllee date: Tue Aug 31 16:42:03 2010 -0700 description: starting to muck about with forestry view diffstat: vcweb/core/models.py | 38 +++++++++++++++++++++++++++++--------- vcweb/forestry/urls.py | 1 + vcweb/forestry/views.py | 32 +++++++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 12 deletions(-) diffs (121 lines): diff -r 0352b9d8e78e -r 5ba301382f1a vcweb/core/models.py --- a/vcweb/core/models.py Mon Aug 30 18:59:51 2010 -0700 +++ b/vcweb/core/models.py Tue Aug 31 16:42:03 2010 -0700 @@ -371,6 +371,7 @@ ('PAUSED', 'Paused'), ('INSTRUCTIONS', 'Instructions'), ('ROUND_IN_PROGRESS', 'Round in progress'), + ('DEBRIEFING', 'Debriefing'), ('COMPLETED', 'Completed'), ) authentication_code = models.CharField(max_length=255) @@ -455,6 +456,13 @@ return self.id.___hash___() class RoundConfiguration(models.Model): + ROUND_TYPE_CHOICES = ( + ('INSTRUCTIONS', 'Instructions'), + ('QUIZ', 'Quiz round'), + ('CHAT', 'Chat round'), + ('PRACTICE', 'Practice round'), + ('PLAY', 'Actual game round'), + ) game_configuration = models.ForeignKey(GameConfiguration) sequence_number = models.PositiveIntegerField() date_created = models.DateTimeField(auto_now_add=True) @@ -465,20 +473,32 @@ duration = models.PositiveIntegerField(default=0) """ instructions, if any, to display before the round begins """ instructions = models.TextField(null=True, blank=True) - """ debriefing, if any, to display before the round begins """ + """ debriefing, if any, to display after the round ends """ debriefing = models.TextField(null=True, blank=True) + round_type = models.CharField(max_length=32, choices=ROUND_TYPE_CHOICES, default='PLAY') + + def get_debriefing(self, participant_id=None, **kwargs): + if self.debriefing: + return self.templatize(self.debriefing, participant_id, kwargs) + else: + logger.debug("No debriefing available for %s" % self) + return None + def get_instructions(self, participant_id=None, **kwargs): - if self.instructions is None: - logger.debug("No instructions available for %s" % self.__unicode__()) - return '' + if self.instructions: + return self.templatize(self.instructions, participant_id, kwargs) else: + logger.debug("No instructions available for %s" % self) + return None + + def templatize(self, template_string, participant_id=None, **kwargs): + if template_string: try: - return Template(self.instructions).substitute(kwargs, round_number=self.sequence_number, participant_id=participant_id) - except ValueError as error: - return "Error while parsing instructions: %s \nAborting." % error - - + return Template(template_string).substitute(kwargs, round_number=self.sequence_number, participant_id=participant_id) + except ValueError as templateError: + return "Error while parsing template_string text: %s" % templateError + return None def __unicode__(self): return "Round # {0} for game {1} ".format(self.sequence_number, self.game_configuration) diff -r 0352b9d8e78e -r 5ba301382f1a vcweb/forestry/urls.py --- a/vcweb/forestry/urls.py Mon Aug 30 18:59:51 2010 -0700 +++ b/vcweb/forestry/urls.py Tue Aug 31 16:42:03 2010 -0700 @@ -8,4 +8,5 @@ url(r'^$', 'index', name='index'), url(r'experimenter/$', 'experimenter', name='experimenter'), url(r'configure/(?P<game_instance_id>\d+)$', 'configure', name='configure-experiment'), + url(r'participate/(?P<game_instance_id>\d+)', 'participate', name='participate'), ) diff -r 0352b9d8e78e -r 5ba301382f1a vcweb/forestry/views.py --- a/vcweb/forestry/views.py Mon Aug 30 18:59:51 2010 -0700 +++ b/vcweb/forestry/views.py Tue Aug 31 16:42:03 2010 -0700 @@ -1,8 +1,12 @@ # Create your views here. -from django.http import HttpResponse, Http404 -from django.shortcuts import render_to_response -from django.template import Context, loader +from django.contrib.auth.decorators import login_required +from django.http import Http404 +from django.shortcuts import render_to_response, redirect from django.template.context import RequestContext +from vcweb.core.models import GameInstance +import logging + +logger = logging.getLogger('forestry.views') def index(request): return render_to_response('forestry/index.html', RequestContext(request)) @@ -13,3 +17,25 @@ def experimenter(request): return Http404() + +@login_required +def participate(request, game_instance_id=None): + if game_instance_id is None: + logger.debug("No game instance id specified, redirecting to forestry index page.") + return redirect('index') + try: + participant = request.user.participant + except AttributeError: + logger.debug("No participant available on logged in user %s" % request.user) + return redirect('index') + try: + game_instance = GameInstance.objects.get(pk=game_instance_id) + return render_to_response('forestry/participate.html', + { 'participant': participant, 'game_instance' : game_instance }, + context_instance=RequestContext(request)) + except GameInstance.DoesNotExist: + logger.warning("No game instance for id [%s]" % game_instance_id) + return redirect('index') + + + |
From: <vir...@li...> - 2010-08-31 01:59:36
|
Subject: hg.virtualcommons 43 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/0352b9d8e78e changeset: 43:0352b9d8e78e user: alllee date: Mon Aug 30 18:59:51 2010 -0700 description: adding metadata to core models to ease development of games including templated instructions / debriefings before each round (may be null / blank) and directives to show instructions for a given group for a given round and maintain elapsed time on GroupRoundData. diffstat: vcweb/core/admin.py | 4 +- vcweb/core/auth.py | 7 -- vcweb/core/models.py | 67 ++++++++++++++++++++++----- vcweb/core/monitor.py | 17 ------- vcweb/core/signals.py | 2 + vcweb/forestry/templates/forestry/index.html | 3 - vcweb/forestry/urls.py | 2 +- vcweb/settings.py | 7 ++- vcweb/urls.py | 6 +- 9 files changed, 68 insertions(+), 47 deletions(-) diffs (317 lines): diff -r f1bc693d33f7 -r 0352b9d8e78e vcweb/core/admin.py --- a/vcweb/core/admin.py Thu Aug 26 16:44:52 2010 -0700 +++ b/vcweb/core/admin.py Mon Aug 30 18:59:51 2010 -0700 @@ -4,8 +4,10 @@ @author: alllee ''' +from Canvas import Group from django.contrib import admin -from vcweb.core.models import * +from vcweb.core.models import DataParameter, RoundParameter, GameConfiguration, \ + RoundConfiguration, Experimenter, Participant, GameInstance, ParticipantGroup admin.site.register(DataParameter) admin.site.register(RoundParameter) diff -r f1bc693d33f7 -r 0352b9d8e78e vcweb/core/auth.py --- a/vcweb/core/auth.py Thu Aug 26 16:44:52 2010 -0700 +++ b/vcweb/core/auth.py Mon Aug 30 18:59:51 2010 -0700 @@ -13,16 +13,10 @@ from django.contrib.auth.backends import ModelBackend from django.contrib.auth.models import User from django.core.validators import email_re - import logging - - - logger = logging.getLogger('vcweb.core.auth') - - class AuthenticationBackend(ModelBackend): def authenticate(self, username=None, password=None): if email_re.search(username): @@ -35,4 +29,3 @@ except User.DoesNotExist: return None return None - diff -r f1bc693d33f7 -r 0352b9d8e78e vcweb/core/models.py --- a/vcweb/core/models.py Thu Aug 26 16:44:52 2010 -0700 +++ b/vcweb/core/models.py Mon Aug 30 18:59:51 2010 -0700 @@ -3,6 +3,7 @@ from django.db import models, transaction from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ +from string import Template from vcweb import settings from vcweb.core import signals import datetime @@ -297,7 +298,7 @@ return [self.namespace] def __unicode__(self): - return self.title + return "title:{0} namespace:{1} - created on {2}, last modified at {3}".format(self.title, self.namespace, self.date_created, self.last_modified) class Meta: ordering = ['namespace', 'date_created'] @@ -306,6 +307,8 @@ name = models.CharField(max_length=255, unique=True) description = models.TextField(null=True, blank=True) url = models.URLField(null=True, blank=True, verify_exists=True) + date_created = models.DateTimeField(auto_now_add=True) + last_modified = models.DateTimeField(auto_now=True) def __unicode__(self): return "{0} ({1})".format(self.name, self.url) @@ -377,6 +380,7 @@ game_configuration = models.ForeignKey(GameConfiguration) status = models.CharField(max_length=32, choices=GAME_STATUS_CHOICES) date_created = models.DateTimeField(auto_now_add=True) + last_modified = models.DateTimeField(auto_now=True) start_date_time = models.DateTimeField(null=True, blank=True) # how long this experiment should run in a date format # 1w2d = 1 week 2 days = 9d @@ -453,10 +457,28 @@ class RoundConfiguration(models.Model): game_configuration = models.ForeignKey(GameConfiguration) sequence_number = models.PositiveIntegerField() + date_created = models.DateTimeField(auto_now_add=True) + last_modified = models.DateTimeField(auto_now=True) """ How long should this round execute before advancing to the next? """ - duration = models.PositiveIntegerField() + duration = models.PositiveIntegerField(default=0) + """ instructions, if any, to display before the round begins """ + instructions = models.TextField(null=True, blank=True) + """ debriefing, if any, to display before the round begins """ + debriefing = models.TextField(null=True, blank=True) + + def get_instructions(self, participant_id=None, **kwargs): + if self.instructions is None: + logger.debug("No instructions available for %s" % self.__unicode__()) + return '' + else: + try: + return Template(self.instructions).substitute(kwargs, round_number=self.sequence_number, participant_id=participant_id) + except ValueError as error: + return "Error while parsing instructions: %s \nAborting." % error + + def __unicode__(self): return "Round # {0} for game {1} ".format(self.sequence_number, self.game_configuration) @@ -475,6 +497,9 @@ ) name = models.CharField(max_length=255) type = models.CharField(max_length=32, choices=PARAMETER_TYPES) + date_created = models.DateTimeField(auto_now_add=True) + last_modified = models.DateTimeField(auto_now=True) + creator = models.ForeignKey(Experimenter) def __unicode__(self): return "{0} ({1})".format(self.name, self.type) @@ -483,6 +508,9 @@ abstract = True ordering = ['name'] +""" +Configuration parameters are used to tune the +""" class ConfigurationParameter(Parameter): def __unicode__(self): return 'Configuration Parameter: ' + self.name @@ -516,7 +544,7 @@ parameter_value = models.CharField(max_length=255) def __unicode__(self): - return "{0} -- Parameter: {1} Value: {2}" % self.round_configuration, self.parameter, self.parameter_value + return "{0} -- Parameter: {1} Value: {2}".format(self.round_configuration, self.parameter, self.parameter_value) class Group(models.Model): number = models.PositiveIntegerField() @@ -524,35 +552,39 @@ game_instance = models.ForeignKey(GameInstance) def __unicode__(self): - return "Group #{0} in {1}" % self.number, self.game_instance + return "Group #{0} in {1}".format(self.number, self.game_instance) class Meta: ordering = ['game_instance', 'number'] +""" +Data values stored for a particular group in a particular round. +""" class GroupRoundData (models.Model): group = models.ForeignKey(Group) round = models.ForeignKey(RoundConfiguration) + """ show instructions before the round begins? """ + show_instructions = models.BooleanField(default=True) + """ show debriefing after the round ends? """ + show_debriefing = models.BooleanField(default=False) + elapsed_time = models.PositiveIntegerField(default=0) def __unicode__(self): - return "Round Data for {0} in {1}" % self.group, self.round + return "Round Data for {0} in {1}".format(self.group, self.round) # class Meta: # db_table = 'vcweb_group_round_data' class DataValue(models.Model): parameter = models.ForeignKey(DataParameter) - parameter_value = models.CharField(max_length=255) + parameter_value = models.CharField(max_length=512) # FIXME: change to DateTimeField time_recorded = models.DateTimeField(auto_now_add=True) game_instance = models.ForeignKey(GameInstance) - @staticmethod - def find(incoming_parameter, incoming_game_instance): - DataValue.objects.filter(parameter=incoming_parameter, game_instance=incoming_game_instance) - def __unicode__(self): - return "Data value: parameter {0}, value {1}, time recorded {2}, game {3}" % self.parameter, self.parameter_value, self.time_recorded, self.game_instance + return "Data value: parameter {0}, value {1}, time recorded {2}, game {3}".format(self.parameter, self.parameter_value, self.time_recorded, self.game_instance) class Meta: abstract = True @@ -581,17 +613,23 @@ date_joined = models.DateTimeField(auto_now_add=True) def __unicode__(self): - return "{0}: {1} (in {2})" % self.participant, self.participant_number, self.group + return "{0}: {1} (in {2})".format(self.participant, self.participant_number, self.group) class Meta: ordering = ['participant_number', 'participant'] -class ParticipantData(models.Model): +""" +holds all participant data for a given round and participant. +""" +class ParticipantRoundData(models.Model): participant = models.ForeignKey(Participant) round_configuration = models.ForeignKey(RoundConfiguration) +""" +The particular participant data value for a given ParticipantRoundData (round + participant entity) +""" class ParticipantDataValue(DataValue): - participant_data = models.ForeignKey(ParticipantData) + participant_data = models.ForeignKey(ParticipantRoundData) class Meta: ordering = [ 'parameter' ] @@ -599,6 +637,7 @@ class SessionTracker(models.Model): login_time = models.DateTimeField(auto_now_add=True) logout_time = models.DateTimeField() + # hook into logout signal? class ExperimenterSession(SessionTracker): experimenter_id = models.ForeignKey(Experimenter) diff -r f1bc693d33f7 -r 0352b9d8e78e vcweb/core/monitor.py --- a/vcweb/core/monitor.py Thu Aug 26 16:44:52 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -''' -The updater module is invoked periodically from an external process to set up the signaling and timing / processing -of experiments in progress. - -@author: alllee -''' - -from vcweb.core.models import GameInstance -from vcweb.core import signals - -from datetime import datetime - -def second_tick_handler(sender, **kwargs): - print "handling second tick signal." - -signals.second_tick.connect(second_tick_handler) - diff -r f1bc693d33f7 -r 0352b9d8e78e vcweb/core/signals.py --- a/vcweb/core/signals.py Thu Aug 26 16:44:52 2010 -0700 +++ b/vcweb/core/signals.py Mon Aug 30 18:59:51 2010 -0700 @@ -12,6 +12,8 @@ round_ended = Signal(providing_args=['game_instance_id', 'round_configuration_id']) second_tick = Signal(providing_args=['time']) +post_login = Signal(providing_args=['user']) +post_logout = Signal(providing_args=['user']) diff -r f1bc693d33f7 -r 0352b9d8e78e vcweb/forestry/templates/forestry/index.html --- a/vcweb/forestry/templates/forestry/index.html Thu Aug 26 16:44:52 2010 -0700 +++ b/vcweb/forestry/templates/forestry/index.html Mon Aug 30 18:59:51 2010 -0700 @@ -5,9 +5,6 @@ {% block header %} <div id='menu'> <ul> - <li class='current_page_item'><a href='{% url home %}' class='first'>Home</a></li> - <li><a href='about/'>About</a></li> - <li><a class='external' href='http://commons.asu.edu/contact'>Contact us</a></li> <li><a href='experimenter/'>Experimenters</a></li> <li><a href='{% url participate %}'>Participate</a></li> </ul> diff -r f1bc693d33f7 -r 0352b9d8e78e vcweb/forestry/urls.py --- a/vcweb/forestry/urls.py Thu Aug 26 16:44:52 2010 -0700 +++ b/vcweb/forestry/urls.py Mon Aug 30 18:59:51 2010 -0700 @@ -5,7 +5,7 @@ @author: alllee ''' urlpatterns = patterns('vcweb.forestry.views', - url(r'$', 'index', name='index'), + url(r'^$', 'index', name='index'), url(r'experimenter/$', 'experimenter', name='experimenter'), url(r'configure/(?P<game_instance_id>\d+)$', 'configure', name='configure-experiment'), ) diff -r f1bc693d33f7 -r 0352b9d8e78e vcweb/settings.py --- a/vcweb/settings.py Thu Aug 26 16:44:52 2010 -0700 +++ b/vcweb/settings.py Mon Aug 30 18:59:51 2010 -0700 @@ -125,4 +125,9 @@ # only needed for windows boxes. Put in settings_local instead? STATIC_BASE_DIR = os.path.join(os.path.dirname(__file__), 'static').replace('\\', '/') -from settings_local import * +try: + from settings_local import * +except ImportError: + print "Couldn't load local settings" + pass + diff -r f1bc693d33f7 -r 0352b9d8e78e vcweb/urls.py --- a/vcweb/urls.py Thu Aug 26 16:44:52 2010 -0700 +++ b/vcweb/urls.py Mon Aug 30 18:59:51 2010 -0700 @@ -1,11 +1,11 @@ from django.conf.urls.defaults import * +from django.contrib import admin +import settings -import settings # FIXME: needed? #import settings (r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.BASE_DIR+'/core/static/', 'show_indexes': True}) # Uncomment the next two lines to enable the admin: -from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', @@ -17,7 +17,7 @@ url(r'^accounts/reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', {'template_name':'password_reset_confirm.html'}), url(r'^accounts/reset/done/$', 'django.contrib.auth.views.password_reset_complete', {'template_name':'password_reset_complete.html'}), - url(r'^forestry/', include('vcweb.forestry.urls', namespace='forestry', app_name='forestry')), + url(r'^forestry/', include('forestry.urls', namespace='forestry', app_name='forestry')), url(r'^admin/', include(admin.site.urls)), url(r'', include('vcweb.core.urls', namespace='core', app_name='vcweb')), # make sure this is last |
From: <vir...@li...> - 2010-08-31 01:59:36
|
Subject: hg.virtualcommons 42 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/f1bc693d33f7 changeset: 42:f1bc693d33f7 user: alllee date: Thu Aug 26 16:44:52 2010 -0700 description: following some django design patterns for templates ala http://uswaretech.com/books/djangodesignpatterns/ diffstat: vcweb/core/models.py | 41 +++++----- vcweb/core/templates/registration/password_reset_form.html | 6 +- vcweb/forestry/templates/forestry-experimenter.html | 4 - vcweb/forestry/templates/forestry-index.html | 31 -------- vcweb/forestry/templates/forestry/experimenter.html | 4 + vcweb/forestry/templates/forestry/index.html | 31 ++++++++ vcweb/forestry/views.py | 4 +- vcweb/update.py | 20 ----- vcweb/urls.py | 5 + vcweb/vcweb | 54 -------------- vcweb/vcweb-updater | 8 -- 11 files changed, 65 insertions(+), 143 deletions(-) diffs (351 lines): diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/core/models.py --- a/vcweb/core/models.py Wed Aug 25 16:33:08 2010 -0700 +++ b/vcweb/core/models.py Thu Aug 26 16:44:52 2010 -0700 @@ -16,11 +16,15 @@ logger = logging.getLogger('vcweb.core.models') # tick handlers - +""" +handles each second tick. Might rethink this and use timed / delayed tasks in celery execute at the end of each round for +controlled experiments and for longer-scale experiments use 1 minute granularity for performance sake. +""" def second_tick_handler(sender, time=None, **kwargs): logger.debug("handling second tick signal at %s" % time) # inspect all active games and update their time left for gameInstance in GameInstance.objects.filter(status='ROUND_IN_PROGRESS'): + # how to invoke a game-type-specific handler here? gameInstance.increment_elapsed_time() gameInstance.save() @@ -377,25 +381,18 @@ # how long this experiment should run in a date format # 1w2d = 1 week 2 days = 9d duration = models.CharField(max_length=32) - """ - how often the game server should tick.. - """ + """ how often the game server should tick. """ tick_duration = models.CharField(max_length=32) - ''' - total elapsed time in seconds since this game was started, incremented by the heartbeat monitor. - ''' + """ total elapsed time in seconds since this game was started, incremented by the heartbeat monitor. """ total_elapsed_time = models.PositiveIntegerField(default=0) - ''' - elapsed time in seconds for the current round. - ''' + """ elapsed time in seconds for the current round. """ current_round_elapsed_time = models.PositiveIntegerField(default=0) """ - If true, signifies that this is an extended game that should execute over the course of a few days or even months - - If false, signifies that this is an experimenter-driven or short-term timer-driven game. + Experimenter driven experiments have checkpoints where the experimenter needs to explicitly signal the system to + move to the next round or stage. """ - is_extended = models.BooleanField(default=False) + is_experimenter_driven = models.BooleanField(default=True) objects = GameInstanceManager() @@ -519,14 +516,15 @@ parameter_value = models.CharField(max_length=255) def __unicode__(self): - return "{0} -- Parameter: {1} Value: {2}".format(self.round_configuration, self.parameter, self.parameter_value) + return "{0} -- Parameter: {1} Value: {2}" % self.round_configuration, self.parameter, self.parameter_value class Group(models.Model): number = models.PositiveIntegerField() max_size = models.PositiveIntegerField() game_instance = models.ForeignKey(GameInstance) + def __unicode__(self): - return "Group #{0} in {1}".format(self.number, self.game_instance) + return "Group #{0} in {1}" % self.number, self.game_instance class Meta: ordering = ['game_instance', 'number'] @@ -537,7 +535,7 @@ round = models.ForeignKey(RoundConfiguration) def __unicode__(self): - return "Round Data for {0} in {1}".format(self.group, self.round) + return "Round Data for {0} in {1}" % self.group, self.round # class Meta: # db_table = 'vcweb_group_round_data' @@ -554,7 +552,7 @@ DataValue.objects.filter(parameter=incoming_parameter, game_instance=incoming_game_instance) def __unicode__(self): - return "Data value: parameter {0}, value {1}, time recorded {2}, game {3}".format(self.parameter, self.parameter_value, self.time_recorded, self.game_instance) + return "Data value: parameter {0}, value {1}, time recorded {2}, game {3}" % self.parameter, self.parameter_value, self.time_recorded, self.game_instance class Meta: abstract = True @@ -571,7 +569,10 @@ class Meta: ordering = ['user'] - +""" +Many-to-many relationship entity storing a participant, group, their participant number in that group, the +round in which +""" class ParticipantGroup(models.Model): participant_number = models.PositiveIntegerField() participant = models.ForeignKey(Participant) @@ -580,7 +581,7 @@ date_joined = models.DateTimeField(auto_now_add=True) def __unicode__(self): - return "{0}: {1} (in {2})".format(self.participant, self.participant_number, self.group) + return "{0}: {1} (in {2})" % self.participant, self.participant_number, self.group class Meta: ordering = ['participant_number', 'participant'] diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/core/templates/registration/password_reset_form.html --- a/vcweb/core/templates/registration/password_reset_form.html Wed Aug 25 16:33:08 2010 -0700 +++ b/vcweb/core/templates/registration/password_reset_form.html Thu Aug 26 16:44:52 2010 -0700 @@ -1,13 +1,11 @@ {% extends "base-vcweb-form.html" %} - - {% block head %} {{ block.super }} <script type='text/javascript'> $(document).ready(function() { - $('#registrationForm').validate(); + $('#resetPasswordForm').validate(); }); </script> @@ -17,7 +15,7 @@ {% block content %} -<form id='registrationForm' action='' method='post'> +<form id='resetPasswordForm' action='' method='post'> <fieldset> <legend>Reset your password</legend> diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/forestry/templates/forestry-experimenter.html --- a/vcweb/forestry/templates/forestry-experimenter.html Wed Aug 25 16:33:08 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -{% extends "base-experimenter.html" %} - -{% block title %} Forestry Experimenter Interface {% endblock %} - \ No newline at end of file diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/forestry/templates/forestry-index.html --- a/vcweb/forestry/templates/forestry-index.html Wed Aug 25 16:33:08 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -{% extends "base-vcweb.html" %} - -{% block title %}Forestry{% endblock %} - -{% block header %} -<div id='menu'> - <ul> - <li class='current_page_item'><a href='{% url home %}' class='first'>Home</a></li> - <li><a href='about/'>About</a></li> - <li><a class='external' href='http://commons.asu.edu/contact'>Contact us</a></li> - <li><a href='experimenter/'>Experimenters</a></li> - <li><a href='{% url participate %}'>Participate</a></li> - </ul> -</div> - - -{% endblock header %} - -{% block content %} -<div id='post'> - <h2 class='title'>Forestry</h2> - <div class='entry'> - The forestry experiment. - - </div> - - - -</div> -{% endblock content %} - diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/forestry/templates/forestry/experimenter.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/forestry/templates/forestry/experimenter.html Thu Aug 26 16:44:52 2010 -0700 @@ -0,0 +1,4 @@ +{% extends "base-experimenter.html" %} + +{% block title %} Forestry Experimenter Interface {% endblock %} + \ No newline at end of file diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/forestry/templates/forestry/index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/forestry/templates/forestry/index.html Thu Aug 26 16:44:52 2010 -0700 @@ -0,0 +1,31 @@ +{% extends "base-vcweb.html" %} + +{% block title %}Forestry{% endblock %} + +{% block header %} +<div id='menu'> + <ul> + <li class='current_page_item'><a href='{% url home %}' class='first'>Home</a></li> + <li><a href='about/'>About</a></li> + <li><a class='external' href='http://commons.asu.edu/contact'>Contact us</a></li> + <li><a href='experimenter/'>Experimenters</a></li> + <li><a href='{% url participate %}'>Participate</a></li> + </ul> +</div> + + +{% endblock header %} + +{% block content %} +<div id='post'> + <h2 class='title'>Forestry</h2> + <div class='entry'> + The forestry experiment. + + </div> + + + +</div> +{% endblock content %} + diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/forestry/views.py --- a/vcweb/forestry/views.py Wed Aug 25 16:33:08 2010 -0700 +++ b/vcweb/forestry/views.py Thu Aug 26 16:44:52 2010 -0700 @@ -5,11 +5,11 @@ from django.template.context import RequestContext def index(request): - return render_to_response('forestry-index.html', RequestContext(request)) + return render_to_response('forestry/index.html', RequestContext(request)) def configure(request): return Http404() def experimenter(request): - return Http404() \ No newline at end of file + return Http404() diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/update.py --- a/vcweb/update.py Wed Aug 25 16:33:08 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -#!/usr/bin/env python - -import os, sys - - -sys.path.append('/home/alllee/workspace/vcweb') -os.environ['DJANGO_SETTINGS_MODULE'] = 'vcweb.settings' - -try: - import settings # Assumed to be in the same directory. -except ImportError: - import sys - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) - sys.exit(1) - -from core.monitor import GameMonitor - -GameMonitor.update() - - diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/urls.py --- a/vcweb/urls.py Wed Aug 25 16:33:08 2010 -0700 +++ b/vcweb/urls.py Thu Aug 26 16:44:52 2010 -0700 @@ -12,6 +12,11 @@ url(r'^$', 'django.views.generic.simple.direct_to_template', {'template':'index.html'}, name='home'), url(r'^about/$', 'django.views.generic.simple.direct_to_template', {'template':'about.html'}, name='about'), url(r'^accounts/password/reset/$', 'django.contrib.auth.views.password_reset', name='password-reset'), + url(r'^accounts/password_reset/$', 'django.contrib.auth.views.password_reset', {'template_name':'password_reset_form.html', 'email_template_name':'userpanel/password_reset_email.html'}), + url(r'^accounts/password_reset/done/$', 'django.contrib.auth.views.password_reset_done', {'template_name':'password_reset_done.html'}), + url(r'^accounts/reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', {'template_name':'password_reset_confirm.html'}), + url(r'^accounts/reset/done/$', 'django.contrib.auth.views.password_reset_complete', {'template_name':'password_reset_complete.html'}), + url(r'^forestry/', include('vcweb.forestry.urls', namespace='forestry', app_name='forestry')), url(r'^admin/', include(admin.site.urls)), url(r'', include('vcweb.core.urls', namespace='core', app_name='vcweb')), diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/vcweb --- a/vcweb/vcweb Wed Aug 25 16:33:08 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -#!/bin/sh - -### BEGIN INIT INFO -# Provides: vcweb -# Default-Start: 4 5 -# Default-Stop: -# Short-Description: Virtual Commons Web external monitoring daemon that pings the VCWEB web application each second. -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -DESC="vcweb monitoring daemon" -DAEMON=/usr/local/bin/vcweb-updater -PIDFILE=/var/run/vcweb.pid - -test -x $DAEMON || exit 0 - -. /lib/lsb/init-functions - -case "$1" in - start) - echo -n "Starting $DESC." - start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON || true - echo -n "$DESC started, pidfile at $PIDFILE" - stop) - echo -n "Stopping $DESC: " - start-stop-daemon --stop --quiet --pidfile $PIDFILE \ - --exec $DAEMON || true - echo "Stopped $DESC" - ;; - restart|force-reload) - echo -n "Restarting $DESC: " - start-stop-daemon --stop --quiet --pidfile \ - $PIDFILE --exec $DAEMON || true - sleep 1 - start-stop-daemon --start --quiet --pidfile \ - $PIDFILE --exec $DAEMON || true - echo "started $DESC." - ;; - reload) - echo -n "Reloading $DESC configuration: " - start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE \ - --exec $DAEMON || true - echo "reloaded $DESC." - ;; - status) - status_of_proc -p $PIDFILE "$DAEMON" vcweb-updater && exit 0 || exit $? - ;; - *) - echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2 - exit 1 - ;; -esac - diff -r ef767a4a4f0f -r f1bc693d33f7 vcweb/vcweb-updater --- a/vcweb/vcweb-updater Wed Aug 25 16:33:08 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -#!/bin/bash - -export DJANGO_SETTINGS_MODULE=settings - -while [ "true" ]; do - python update.py - sleep 1 -done |
From: <vir...@li...> - 2010-08-25 23:33:04
|
Subject: hg.virtualcommons 38 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/65bcad53af0a changeset: 38:65bcad53af0a user: alllee date: Mon Aug 23 16:54:36 2010 -0700 description: adding celery django integration to settings, removing forestry threading stubs diffstat: vcweb/forestry/models.py | 10 ---------- vcweb/settings.py | 12 ++++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diffs (47 lines): diff -r 0ac73ab3d01d -r 65bcad53af0a vcweb/forestry/models.py --- a/vcweb/forestry/models.py Fri Aug 20 17:34:48 2010 -0700 +++ b/vcweb/forestry/models.py Mon Aug 23 16:54:36 2010 -0700 @@ -11,13 +11,3 @@ ''' check all forestry game instances ''' - -def start_monitor_thread(sender, **kwargs): - t = threading.Thread(target=forestry_second_tick, kwargs) - t.setDaemon(True) - t.start() - - -second_tick.connect(start_monitor_thread, sender=None) - - diff -r 0ac73ab3d01d -r 65bcad53af0a vcweb/settings.py --- a/vcweb/settings.py Fri Aug 20 17:34:48 2010 -0700 +++ b/vcweb/settings.py Mon Aug 23 16:54:36 2010 -0700 @@ -12,6 +12,7 @@ LOCAL_DEVELOPMENT = True ADMINS = ( + ('Allen Lee', 'all...@as...') # ('Your Name', 'you...@do...'), ) @@ -92,7 +93,18 @@ 'django.contrib.admin', 'vcweb.core', 'vcweb.forestry', + 'djcelery', ) +BROKER_HOST = "localhost" +BROKER_PORT = 5672 +BROKER_USER = "vcweb-celery" +BROKER_PASSWORD = 'override this in settings_local.py' +BROKER_VHOST = "vcweb.rabbitmq.host" + + +import djcelery + +djcelery.setup_loader() # activation window ACCOUNT_ACTIVATION_DAYS = 30 |
From: <vir...@li...> - 2010-08-25 23:33:04
|
Subject: hg.virtualcommons 41 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/ef767a4a4f0f changeset: 41:ef767a4a4f0f user: alllee date: Wed Aug 25 16:33:08 2010 -0700 description: providing defaults for elapsed time diffstat: vcweb/core/models.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (17 lines): diff -r b14a9ccd525a -r ef767a4a4f0f vcweb/core/models.py --- a/vcweb/core/models.py Wed Aug 25 16:24:23 2010 -0700 +++ b/vcweb/core/models.py Wed Aug 25 16:33:08 2010 -0700 @@ -385,11 +385,11 @@ ''' total elapsed time in seconds since this game was started, incremented by the heartbeat monitor. ''' - total_elapsed_time = models.PositiveIntegerField() + total_elapsed_time = models.PositiveIntegerField(default=0) ''' elapsed time in seconds for the current round. ''' - current_round_elapsed_time = models.PositiveIntegerField() + current_round_elapsed_time = models.PositiveIntegerField(default=0) """ If true, signifies that this is an extended game that should execute over the course of a few days or even months |
From: <vir...@li...> - 2010-08-25 23:33:04
|
Subject: hg.virtualcommons 40 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/b14a9ccd525a changeset: 40:b14a9ccd525a user: alllee date: Wed Aug 25 16:24:23 2010 -0700 description: forgot to add celery tasks.py and updating models to work out scheduling support diffstat: vcweb/core/models.py | 41 ++++++++++++++++++++++++++++++++++++----- vcweb/core/tasks.py | 19 +++++++++++++++++++ vcweb/settings.py | 2 +- 3 files changed, 56 insertions(+), 6 deletions(-) diffs (117 lines): diff -r c1c640ec0fe2 -r b14a9ccd525a vcweb/core/models.py --- a/vcweb/core/models.py Wed Aug 25 14:58:43 2010 -0700 +++ b/vcweb/core/models.py Wed Aug 25 16:24:23 2010 -0700 @@ -15,9 +15,14 @@ logger = logging.getLogger('vcweb.core.models') +# tick handlers + def second_tick_handler(sender, time=None, **kwargs): logger.debug("handling second tick signal at %s" % time) - + # inspect all active games and update their time left + for gameInstance in GameInstance.objects.filter(status='ROUND_IN_PROGRESS'): + gameInstance.increment_elapsed_time() + gameInstance.save() signals.second_tick.connect(second_tick_handler, sender=None) @@ -356,6 +361,9 @@ GAME_STATUS_CHOICES = ( ('INACTIVE', 'Not active'), ('ACTIVE', 'Active'), + ('PAUSED', 'Paused'), + ('INSTRUCTIONS', 'Instructions'), + ('ROUND_IN_PROGRESS', 'Round in progress'), ('COMPLETED', 'Completed'), ) authentication_code = models.CharField(max_length=255) @@ -373,10 +381,17 @@ how often the game server should tick.. """ tick_duration = models.CharField(max_length=32) - end_date_time = models.DateTimeField(null=True, blank=True) + + ''' + total elapsed time in seconds since this game was started, incremented by the heartbeat monitor. + ''' + total_elapsed_time = models.PositiveIntegerField() + ''' + elapsed time in seconds for the current round. + ''' + current_round_elapsed_time = models.PositiveIntegerField() """ - If true, signifies that this is an extended game that should execute over the course of a few days or even months, utilizes cron for scheduling - of events. + If true, signifies that this is an extended game that should execute over the course of a few days or even months If false, signifies that this is an experimenter-driven or short-term timer-driven game. """ @@ -384,6 +399,23 @@ objects = GameInstanceManager() + def advance_to_next_round(self): + self.current_round_elapsed_time = 0 + self.current_round_number += 1 + self.status = 'INSTRUCTIONS' + + def start_round(self): + self.status = 'ROUND_IN_PROGRESS' + + def increment_elapsed_time(self): + self.total_elapsed_time += 1 + self.current_round_elapsed_time += 1 + + + @property + def get_current_round(self): + return RoundConfiguration.objects.get(game_configuration=self.game_configuration, sequence_number=self.current_round_number) + @property def url(self, request): user = request.user @@ -426,7 +458,6 @@ sequence_number = models.PositiveIntegerField() """ How long should this round execute before advancing to the next? - """ duration = models.PositiveIntegerField() diff -r c1c640ec0fe2 -r b14a9ccd525a vcweb/core/tasks.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/tasks.py Wed Aug 25 16:24:23 2010 -0700 @@ -0,0 +1,19 @@ +''' +The updater module is invoked periodically from an external process to set up the signaling and timing / processing +of experiments in progress. + +@author: alllee +''' + +from celery.decorators import periodic_task +from datetime import datetime, timedelta +from vcweb.core import signals + + +@periodic_task(run_every=timedelta(seconds=1), ignore_result=True) +def every_second(): + # use signal or just update game instance models directly here? + signals.second_tick.send(sender=None, time=datetime.now()) + + + diff -r c1c640ec0fe2 -r b14a9ccd525a vcweb/settings.py --- a/vcweb/settings.py Wed Aug 25 14:58:43 2010 -0700 +++ b/vcweb/settings.py Wed Aug 25 16:24:23 2010 -0700 @@ -104,7 +104,7 @@ # celerybeat configuration CELERYBEAT_MAX_LOOP_INTERVAL = 5 CELERYBEAT_LOG_FILE = 'celerybeat.log' -CELERYBEAT_LOG_LEVEL = 'ERROR' +CELERYBEAT_LOG_LEVEL = 'DEBUG' import djcelery |
From: <vir...@li...> - 2010-08-25 23:33:04
|
Subject: hg.virtualcommons 39 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/c1c640ec0fe2 changeset: 39:c1c640ec0fe2 user: alllee date: Wed Aug 25 14:58:43 2010 -0700 description: celery + rabbitmq integration seems to be working now. In order to test it out we need to make sure three services are running: 1. celerybeat (python manage.py celerybeat) 2. celeryd (python manage.py celeryd) 3. rabbitmq (/etc/init.d/rabbitmq-server if installed properly as a system level package) one issue with the current implementation is that /var/log/rabbitmq/rabbit.log gets huge with the every-second tick. It looks like rabbitmq logging is not configurable to the degree where we can specify a loglevel and have it not log INFO events. I don't particularly want to disable the rabbit.log but we may have to do so to deal with the enormous number of 1s pings we're generating from a 1s celerybeat schedule. diffstat: vcweb/core/admin.py | 1 - vcweb/core/models.py | 8 ++++++++ vcweb/core/monitor.py | 11 ++++------- vcweb/settings.py | 5 +++++ 4 files changed, 17 insertions(+), 8 deletions(-) diffs (70 lines): diff -r 65bcad53af0a -r c1c640ec0fe2 vcweb/core/admin.py --- a/vcweb/core/admin.py Mon Aug 23 16:54:36 2010 -0700 +++ b/vcweb/core/admin.py Wed Aug 25 14:58:43 2010 -0700 @@ -7,7 +7,6 @@ from django.contrib import admin from vcweb.core.models import * -admin.site.register(GameMetadata) admin.site.register(DataParameter) admin.site.register(RoundParameter) admin.site.register(GameConfiguration) diff -r 65bcad53af0a -r c1c640ec0fe2 vcweb/core/models.py --- a/vcweb/core/models.py Mon Aug 23 16:54:36 2010 -0700 +++ b/vcweb/core/models.py Wed Aug 25 14:58:43 2010 -0700 @@ -4,6 +4,7 @@ from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ from vcweb import settings +from vcweb.core import signals import datetime import hashlib import logging @@ -13,6 +14,13 @@ SHA1_RE = re.compile('^[a-f0-9]{40}$') logger = logging.getLogger('vcweb.core.models') + +def second_tick_handler(sender, time=None, **kwargs): + logger.debug("handling second tick signal at %s" % time) + + +signals.second_tick.connect(second_tick_handler, sender=None) + # FIXME: separate accounts / registration / experimenter / participant app from the core app # registration manager included / forked from http://bitbucket.org/ubernostrum/django-registration/ diff -r 65bcad53af0a -r c1c640ec0fe2 vcweb/core/monitor.py --- a/vcweb/core/monitor.py Mon Aug 23 16:54:36 2010 -0700 +++ b/vcweb/core/monitor.py Wed Aug 25 14:58:43 2010 -0700 @@ -10,11 +10,8 @@ from datetime import datetime -class GameMonitor(): - @classmethod - def update(cls): - now = datetime.now() - print "Sending second tick signal at %s" % now - print ["\n\t" + gameInstance + "\n" for gameInstance in GameInstance.objects.get_all_active()] - signals.second_tick.send(sender=cls, now) +def second_tick_handler(sender, **kwargs): + print "handling second tick signal." +signals.second_tick.connect(second_tick_handler) + diff -r 65bcad53af0a -r c1c640ec0fe2 vcweb/settings.py --- a/vcweb/settings.py Mon Aug 23 16:54:36 2010 -0700 +++ b/vcweb/settings.py Wed Aug 25 14:58:43 2010 -0700 @@ -101,6 +101,11 @@ BROKER_PASSWORD = 'override this in settings_local.py' BROKER_VHOST = "vcweb.rabbitmq.host" +# celerybeat configuration +CELERYBEAT_MAX_LOOP_INTERVAL = 5 +CELERYBEAT_LOG_FILE = 'celerybeat.log' +CELERYBEAT_LOG_LEVEL = 'ERROR' + import djcelery |
From: <vir...@li...> - 2010-08-21 00:34:55
|
Subject: hg.virtualcommons 37 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/0ac73ab3d01d changeset: 37:0ac73ab3d01d user: alllee date: Fri Aug 20 17:34:48 2010 -0700 description: incorporating Django signals / external process to help trigger second ticks. diffstat: vcweb/core/auth.py | 16 +++--------- vcweb/core/forms.py | 11 ++------ vcweb/core/models.py | 58 +++++++++++++++++++++++++++++++++++------------ vcweb/core/monitor.py | 20 ++++++++++++++++ vcweb/core/signals.py | 18 ++++++++++++++ vcweb/forestry/models.py | 23 +++++++++++++++++++ vcweb/update.py | 20 ++++++++++++++++ vcweb/vcweb | 54 ++++++++++++++++++++++++++++++++++++++++++++ vcweb/vcweb-updater | 8 ++++++ 9 files changed, 193 insertions(+), 35 deletions(-) diffs (353 lines): diff -r 463bde157552 -r 0ac73ab3d01d vcweb/core/auth.py --- a/vcweb/core/auth.py Tue Aug 17 15:20:50 2010 -0700 +++ b/vcweb/core/auth.py Fri Aug 20 17:34:48 2010 -0700 @@ -11,25 +11,17 @@ from django.contrib.auth.backends import ModelBackend +from django.contrib.auth.models import User +from django.core.validators import email_re -from django.core.validators import email_re -from vcweb.core.models import * +import logging + logger = logging.getLogger('vcweb.core.auth') -def is_experimenter(user): - try: - return user.experimenter - except Experimenter.DoesNotExist: - return None -def is_participant(user): - try: - return user.participant - except Participant.DoesNotExist: - return None class AuthenticationBackend(ModelBackend): def authenticate(self, username=None, password=None): diff -r 463bde157552 -r 0ac73ab3d01d vcweb/core/forms.py --- a/vcweb/core/forms.py Tue Aug 17 15:20:50 2010 -0700 +++ b/vcweb/core/forms.py Fri Aug 20 17:34:48 2010 -0700 @@ -4,18 +4,15 @@ @author: alllee ''' from django import forms -from django.contrib import admin -from django.contrib.auth.admin import UserAdmin -from django.contrib.auth.models import User from django.forms import widgets #from django.forms import ModelForm #from vcweb.core.models import Experimenter -EMAIL_ATTRIBUTES = { 'class' : 'required email' } +REQUIRED_EMAIL_ATTRIBUTES = { 'class' : 'required email' } REQUIRED_ATTRIBUTES = { 'class' : 'required' } class RegistrationForm(forms.Form): - email = forms.EmailField(required=True, widget=widgets.TextInput(attrs=EMAIL_ATTRIBUTES)) + email = forms.EmailField(required=True, widget=widgets.TextInput(attrs=REQUIRED_EMAIL_ATTRIBUTES)) password = forms.CharField(required=True, widget=widgets.PasswordInput(attrs=REQUIRED_ATTRIBUTES)) confirm_password = forms.CharField(required=True, widget=widgets.PasswordInput(attrs=REQUIRED_ATTRIBUTES)) # these are hidden unless they check "experimenter request" @@ -24,9 +21,7 @@ last_name = forms.CharField(required=True, widget=widgets.TextInput(attrs=REQUIRED_ATTRIBUTES)) institution = forms.CharField(required=True, widget=widgets.TextInput(attrs=REQUIRED_ATTRIBUTES)) - - class LoginForm(forms.Form): - email = forms.EmailField(required=True, widget=widgets.TextInput(attrs=EMAIL_ATTRIBUTES)) + email = forms.EmailField(required=True, widget=widgets.TextInput(attrs=REQUIRED_EMAIL_ATTRIBUTES)) password = forms.CharField(required=True, widget=widgets.PasswordInput(attrs=REQUIRED_ATTRIBUTES)) diff -r 463bde157552 -r 0ac73ab3d01d vcweb/core/models.py --- a/vcweb/core/models.py Tue Aug 17 15:20:50 2010 -0700 +++ b/vcweb/core/models.py Fri Aug 20 17:34:48 2010 -0700 @@ -9,7 +9,6 @@ import logging import random import re -from vcweb.core import auth SHA1_RE = re.compile('^[a-f0-9]{40}$') @@ -256,15 +255,6 @@ self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL) -## may use for urls.attribute_name trick shown in http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/ -#def attrproperty(getter_function): -# class _Object(object): -# def __init__(self, obj): -# self.obj = obj -# def __getattr__(self, attr): -# return getter_function(self.obj, attr) -# return property(_Object) - # manager classes class GameMetadataManager(models.Manager): @@ -304,8 +294,13 @@ return "{0} ({1})".format(self.name, self.url) class CommonsUser(models.Model): - # for docs on related_name see http://docs.djangoproject.com/en/dev/topics/db/models/#be-careful-with-related-name - # this related name makes user.experimenter and user.participant resolvable + """ + for docs on related_name see + http://docs.djangoproject.com/en/dev/topics/db/models/#be-careful-with-related-name + this related name makes user.experimenter and user.participant resolvable. + FIXME: should revisit to see if this is recommended practice. + (either one or the other) + """ user = models.OneToOneField(User, related_name='%(class)s', verbose_name=u'Django User', unique=True) failed_password_attempts = models.PositiveIntegerField(default=0) institution = models.ForeignKey(Institution, null=True, blank=True) @@ -341,6 +336,12 @@ class Meta: ordering = ['game', 'creator', 'date_created'] + +class GameInstanceManager(models.Manager): + def get_all_active(self): + return self.filter(status='ACTIVE') + + # an actual instance of a game; represents a concrete # parameterization of this game. class GameInstance(models.Model): @@ -357,17 +358,29 @@ status = models.CharField(max_length=32, choices=GAME_STATUS_CHOICES) date_created = models.DateTimeField(auto_now_add=True) start_date_time = models.DateTimeField(null=True, blank=True) - # how long this experiment should run + # how long this experiment should run in a date format + # 1w2d = 1 week 2 days = 9d duration = models.CharField(max_length=32) - # duration of each tick. + """ + how often the game server should tick.. + """ tick_duration = models.CharField(max_length=32) end_date_time = models.DateTimeField(null=True, blank=True) + """ + If true, signifies that this is an extended game that should execute over the course of a few days or even months, utilizes cron for scheduling + of events. + + If false, signifies that this is an experimenter-driven or short-term timer-driven game. + """ + is_extended = models.BooleanField(default=False) + + objects = GameInstanceManager() @property def url(self, request): user = request.user if user.is_authenticated(): - return "/{0}/{1}".format("participant" if auth.is_participant(user) else "experimenter", self.url_id) + return "/{0}/{1}".format("participant" if is_participant(user) else "experimenter", self.url_id) else: return self.namespace @@ -403,6 +416,11 @@ class RoundConfiguration(models.Model): game_configuration = models.ForeignKey(GameConfiguration) sequence_number = models.PositiveIntegerField() + """ + How long should this round execute before advancing to the next? + + """ + duration = models.PositiveIntegerField() def __unicode__(self): return "Round # {0} for game {1} ".format(self.sequence_number, self.game_configuration) @@ -548,6 +566,16 @@ class ParticipantSession(SessionTracker): participant_id = models.ForeignKey(Participant) +def is_experimenter(user): + try: + return user.experimenter + except Experimenter.DoesNotExist: + return None +def is_participant(user): + try: + return user.participant + except Participant.DoesNotExist: + return None diff -r 463bde157552 -r 0ac73ab3d01d vcweb/core/monitor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/monitor.py Fri Aug 20 17:34:48 2010 -0700 @@ -0,0 +1,20 @@ +''' +The updater module is invoked periodically from an external process to set up the signaling and timing / processing +of experiments in progress. + +@author: alllee +''' + +from vcweb.core.models import GameInstance +from vcweb.core import signals + +from datetime import datetime + +class GameMonitor(): + @classmethod + def update(cls): + now = datetime.now() + print "Sending second tick signal at %s" % now + print ["\n\t" + gameInstance + "\n" for gameInstance in GameInstance.objects.get_all_active()] + signals.second_tick.send(sender=cls, now) + diff -r 463bde157552 -r 0ac73ab3d01d vcweb/core/signals.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/signals.py Fri Aug 20 17:34:48 2010 -0700 @@ -0,0 +1,18 @@ +''' +Created on Aug 19, 2010 + +@author: alllee +''' + +from django.dispatch import Signal + + +game_started = Signal(providing_args=["game_instance_id", "time", "experimenter"]) +round_started = Signal(providing_args=["game_instance_id", 'round_configuration_id']) +round_ended = Signal(providing_args=['game_instance_id', 'round_configuration_id']) +second_tick = Signal(providing_args=['time']) + + + + + diff -r 463bde157552 -r 0ac73ab3d01d vcweb/forestry/models.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/forestry/models.py Fri Aug 20 17:34:48 2010 -0700 @@ -0,0 +1,23 @@ +from django.db import models +from vcweb.core.signals import * +import threading + +# Create your models here. + + + +def forestry_second_tick(self): + print "Monitoring Forestry Game Instances." + ''' + check all forestry game instances + ''' + +def start_monitor_thread(sender, **kwargs): + t = threading.Thread(target=forestry_second_tick, kwargs) + t.setDaemon(True) + t.start() + + +second_tick.connect(start_monitor_thread, sender=None) + + diff -r 463bde157552 -r 0ac73ab3d01d vcweb/update.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/update.py Fri Aug 20 17:34:48 2010 -0700 @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +import os, sys + + +sys.path.append('/home/alllee/workspace/vcweb') +os.environ['DJANGO_SETTINGS_MODULE'] = 'vcweb.settings' + +try: + import settings # Assumed to be in the same directory. +except ImportError: + import sys + sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) + sys.exit(1) + +from core.monitor import GameMonitor + +GameMonitor.update() + + diff -r 463bde157552 -r 0ac73ab3d01d vcweb/vcweb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/vcweb Fri Aug 20 17:34:48 2010 -0700 @@ -0,0 +1,54 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: vcweb +# Default-Start: 4 5 +# Default-Stop: +# Short-Description: Virtual Commons Web external monitoring daemon that pings the VCWEB web application each second. +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +DESC="vcweb monitoring daemon" +DAEMON=/usr/local/bin/vcweb-updater +PIDFILE=/var/run/vcweb.pid + +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +case "$1" in + start) + echo -n "Starting $DESC." + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON || true + echo -n "$DESC started, pidfile at $PIDFILE" + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --pidfile $PIDFILE \ + --exec $DAEMON || true + echo "Stopped $DESC" + ;; + restart|force-reload) + echo -n "Restarting $DESC: " + start-stop-daemon --stop --quiet --pidfile \ + $PIDFILE --exec $DAEMON || true + sleep 1 + start-stop-daemon --start --quiet --pidfile \ + $PIDFILE --exec $DAEMON || true + echo "started $DESC." + ;; + reload) + echo -n "Reloading $DESC configuration: " + start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE \ + --exec $DAEMON || true + echo "reloaded $DESC." + ;; + status) + status_of_proc -p $PIDFILE "$DAEMON" vcweb-updater && exit 0 || exit $? + ;; + *) + echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2 + exit 1 + ;; +esac + diff -r 463bde157552 -r 0ac73ab3d01d vcweb/vcweb-updater --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/vcweb-updater Fri Aug 20 17:34:48 2010 -0700 @@ -0,0 +1,8 @@ +#!/bin/bash + +export DJANGO_SETTINGS_MODULE=settings + +while [ "true" ]; do + python update.py + sleep 1 +done |
From: <vir...@li...> - 2010-08-21 00:34:55
|
Subject: hg.virtualcommons 36 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/463bde157552 changeset: 36:463bde157552 user: alllee date: Tue Aug 17 15:20:50 2010 -0700 description: adding vcweb forestry fixtures for loading initial forestry game metadata, added natural_key support for core.GameMetadata diffstat: vcweb/core/fixtures/initial_data.json | 14 -------------- vcweb/core/models.py | 24 +++++++++++++----------- vcweb/forestry/fixtures/initial_data.json | 23 +++++++++++++++++++++++ 3 files changed, 36 insertions(+), 25 deletions(-) diffs (116 lines): diff -r 6c6423845a89 -r 463bde157552 vcweb/core/fixtures/initial_data.json --- a/vcweb/core/fixtures/initial_data.json Tue Aug 03 18:45:52 2010 -0700 +++ b/vcweb/core/fixtures/initial_data.json Tue Aug 17 15:20:50 2010 -0700 @@ -1,20 +1,6 @@ [ { "pk": 1, - "model": "core.gamemetadata", - "fields": { - "description": "Web-based version of the forestry field experiments.", - "title": "Forestry Web Experiment", - "namespace": "forestry", - "last_modified": "2010-08-01", - "date_created": "2010-08-01", - "logo_url": "", - "about_url": "http://commons.asu.edu", - "default_game_configuration": null - } - }, - { - "pk": 1, "model": "core.institution", "fields": { "url": "http://www.asu.edu", diff -r 6c6423845a89 -r 463bde157552 vcweb/core/models.py --- a/vcweb/core/models.py Tue Aug 03 18:45:52 2010 -0700 +++ b/vcweb/core/models.py Tue Aug 17 15:20:50 2010 -0700 @@ -265,6 +265,12 @@ # return getter_function(self.obj, attr) # return property(_Object) +# manager classes +class GameMetadataManager(models.Manager): + + def get_by_natural_key(self, key): + return self.get(namespace=key) + # Create your models here. class GameMetadata(models.Model): @@ -278,6 +284,11 @@ logo_url = models.URLField(null=True, blank=True, verify_exists=True) default_game_configuration = models.ForeignKey('GameConfiguration', null=True, blank=True) + objects = GameMetadataManager() + + def natural_key(self): + return [self.namespace] + def __unicode__(self): return self.title @@ -285,7 +296,7 @@ ordering = ['namespace', 'date_created'] class Institution(models.Model): - name = models.CharField(max_length=255) + name = models.CharField(max_length=255, unique=True) description = models.TextField(null=True, blank=True) url = models.URLField(null=True, blank=True, verify_exists=True) @@ -315,7 +326,6 @@ class Meta: ordering = ['user'] - class GameConfiguration(models.Model): game = models.ForeignKey(GameMetadata) creator = models.ForeignKey(Experimenter) @@ -497,18 +507,10 @@ class Meta: ordering = [ 'parameter' ] -class ParticipantManager(models.Manager): - def get_all_game_instances(self, participant_id): - # generate appropriate query using Groups? - # link from groups to game instances - participant_groups = ParticipantGroup.objects.filter(participant__id=participant_id) - - return GameInstance.objects.filter(pk__in=[]) - class Participant(CommonsUser): can_receive_invitations = models.BooleanField(default=False) group = models.ManyToManyField(Group, through='ParticipantGroup', related_name='groups') - objects = ParticipantManager() +# objects = ParticipantManager() class Meta: ordering = ['user'] diff -r 6c6423845a89 -r 463bde157552 vcweb/forestry/fixtures/initial_data.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/forestry/fixtures/initial_data.json Tue Aug 17 15:20:50 2010 -0700 @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "core.gamemetadata", + "fields": { + "description": "Web-based version of the forestry field experiments.", + "title": "Forestry Web Experiment", + "namespace": "forestry", + "about_url": "http://commons.asu.edu" + } + }, + { + "pk": 1, + "model": "core.gameconfiguration", + "fields": { + "name": "Forestry Default Configuration", + "creator": 1, + "maximum_number_of_participants": 20, + "game": ["forestry"], + "is_public": true + } + } +] |
From: <al...@us...> - 2010-08-17 01:06:43
|
Revision: 532 http://virtualcommons.svn.sourceforge.net/virtualcommons/?rev=532&view=rev Author: alllee Date: 2010-08-17 01:06:37 +0000 (Tue, 17 Aug 2010) Log Message: ----------- forgot to add webdefault.xml file needed by maven-jetty-plugin Added Paths: ----------- foraging/trunk/src/main/resources/web/webdefault.xml Added: foraging/trunk/src/main/resources/web/webdefault.xml =================================================================== --- foraging/trunk/src/main/resources/web/webdefault.xml (rev 0) +++ foraging/trunk/src/main/resources/web/webdefault.xml 2010-08-17 01:06:37 UTC (rev 532) @@ -0,0 +1,414 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!-- +vim:sts=2:sw=2 +--> + +<!-- ===================================================================== --> +<!-- This file contains the default descriptor for web applications. --> +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> +<!-- The intent of this descriptor is to include jetty specific or common --> +<!-- configuration for all webapps. If a context has a webdefault.xml --> +<!-- descriptor, it is applied before the contexts own web.xml file --> +<!-- --> +<!-- A context may be assigned a default descriptor by: --> +<!-- + Calling WebApplicationContext.setDefaultsDescriptor --> +<!-- + Passed an arg to addWebApplications --> +<!-- --> +<!-- This file is used both as the resource within the jetty.jar (which is --> +<!-- used as the default if no explicit defaults descriptor is set) and it --> +<!-- is copied to the etc directory of the Jetty distro and explicitly --> +<!-- by the jetty.xml file. --> +<!-- --> +<!-- ===================================================================== --> +<web-app + xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" + metadata-complete="true" + version="2.5"> + + <description> + Default web.xml file. + This file is applied to a Web application before it's own WEB-INF/web.xml file + </description> + + + <!-- ==================================================================== --> + <!-- Context params to control Session Cookies --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- UNCOMMENT TO ACTIVATE + <context-param> + <param-name>org.mortbay.jetty.servlet.SessionDomain</param-name> + <param-value>127.0.0.1</param-value> + </context-param> + + <context-param> + <param-name>org.mortbay.jetty.servlet.SessionPath</param-name> + <param-value>/</param-value> + </context-param> + + <context-param> + <param-name>org.mortbay.jetty.servlet.MaxAge</param-name> + <param-value>-1</param-value> + </context-param> + --> + + <context-param> + <param-name>org.mortbay.jetty.webapp.NoTLDJarPattern</param-name> + <param-value>start.jar|ant-.*\.jar|dojo-.*\.jar|jetty-.*\.jar|jsp-api-.*\.jar|junit-.*\.jar|servlet-api-.*\.jar|dnsns\.jar|rt\.jar|jsse\.jar|tools\.jar|sunpkcs11\.jar|sunjce_provider\.jar|xerces.*\.jar</param-value> + </context-param> + + + + <!-- ==================================================================== --> + <!-- The default servlet. --> + <!-- This servlet, normally mapped to /, provides the handling for static --> + <!-- content, OPTIONS and TRACE methods for the context. --> + <!-- The following initParameters are supported: --> + <!-- --> + <!-- acceptRanges If true, range requests and responses are --> + <!-- supported --> + <!-- --> + <!-- dirAllowed If true, directory listings are returned if no --> + <!-- welcome file is found. Else 403 Forbidden. --> + <!-- --> + <!-- redirectWelcome If true, redirect welcome file requests --> + <!-- else use request dispatcher forwards --> + <!-- --> + <!-- gzip If set to true, then static content will be served--> + <!-- as gzip content encoded if a matching resource is --> + <!-- found ending with ".gz" --> + <!-- --> + <!-- resoureBase Can be set to replace the context resource base --> + <!-- --> + <!-- relativeResourceBase --> + <!-- Set with a pathname relative to the base of the --> + <!-- servlet context root. Useful for only serving --> + <!-- static content from only specific subdirectories. --> + <!-- --> + <!-- useFileMappedBuffer --> + <!-- If set to true (the default), a memory mapped --> + <!-- file buffer will be used to serve static content --> + <!-- when using an NIO connector. Setting this value --> + <!-- to false means that a direct buffer will be used --> + <!-- instead. If you are having trouble with Windows --> + <!-- file locking, set this to false. --> + <!-- --> + <!-- cacheControl If set, all static content will have this value --> + <!-- set as the cache-control header. --> + <!-- --> + <!-- maxCacheSize Maximum size of the static resource cache --> + <!-- --> + <!-- maxCachedFileSize Maximum size of any single file in the cache --> + <!-- --> + <!-- maxCachedFiles Maximum number of files in the cache --> + <!-- --> + <!-- cacheType "nio", "bio" or "both" to determine the type(s) --> + <!-- of resource cache. A bio cached buffer may be used--> + <!-- by nio but is not as efficient as a nio buffer. --> + <!-- An nio cached buffer may not be used by bio. --> + <!-- --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <servlet> + <servlet-name>default</servlet-name> + <servlet-class>org.mortbay.jetty.servlet.DefaultServlet</servlet-class> + <init-param> + <param-name>aliases</param-name> + <param-value>true</param-value> + </init-param> + <init-param> + <param-name>acceptRanges</param-name> + <param-value>true</param-value> + </init-param> + <init-param> + <param-name>dirAllowed</param-name> + <param-value>true</param-value> + </init-param> + <init-param> + <param-name>redirectWelcome</param-name> + <param-value>false</param-value> + </init-param> + <init-param> + <param-name>maxCacheSize</param-name> + <param-value>256000000</param-value> + </init-param> + <init-param> + <param-name>maxCachedFileSize</param-name> + <param-value>10000000</param-value> + </init-param> + <init-param> + <param-name>maxCachedFiles</param-name> + <param-value>1000</param-value> + </init-param> + <init-param> + <param-name>cacheType</param-name> + <param-value>both</param-value> + </init-param> + <init-param> + <param-name>gzip</param-name> + <param-value>true</param-value> + </init-param> + <init-param> + <param-name>useFileMappedBuffer</param-name> + <param-value>true</param-value> + </init-param> + <!-- + <init-param> + <param-name>cacheControl</param-name> + <param-value>max-age=3600,public</param-value> + </init-param> + --> + <load-on-startup>0</load-on-startup> + </servlet> + + <servlet-mapping> + <servlet-name>default</servlet-name> + <url-pattern>/</url-pattern> + </servlet-mapping> + + + <!-- ==================================================================== --> + <!-- JSP Servlet --> + <!-- This is the jasper JSP servlet from the jakarta project --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- The JSP page compiler and execution servlet, which is the mechanism --> + <!-- used by Glassfish to support JSP pages. Traditionally, this servlet --> + <!-- is mapped to URL patterh "*.jsp". This servlet supports the --> + <!-- following initialization parameters (default values are in square --> + <!-- brackets): --> + <!-- --> + <!-- checkInterval If development is false and reloading is true, --> + <!-- background compiles are enabled. checkInterval --> + <!-- is the time in seconds between checks to see --> + <!-- if a JSP page needs to be recompiled. [300] --> + <!-- --> + <!-- compiler Which compiler Ant should use to compile JSP --> + <!-- pages. See the Ant documenation for more --> + <!-- information. [javac] --> + <!-- --> + <!-- classdebuginfo Should the class file be compiled with --> + <!-- debugging information? [true] --> + <!-- --> + <!-- classpath What class path should I use while compiling --> + <!-- generated servlets? [Created dynamically --> + <!-- based on the current web application] --> + <!-- Set to ? to make the container explicitly set --> + <!-- this parameter. --> + <!-- --> + <!-- development Is Jasper used in development mode (will check --> + <!-- for JSP modification on every access)? [true] --> + <!-- --> + <!-- enablePooling Determines whether tag handler pooling is --> + <!-- enabled [true] --> + <!-- --> + <!-- fork Tell Ant to fork compiles of JSP pages so that --> + <!-- a separate JVM is used for JSP page compiles --> + <!-- from the one Tomcat is running in. [true] --> + <!-- --> + <!-- ieClassId The class-id value to be sent to Internet --> + <!-- Explorer when using <jsp:plugin> tags. --> + <!-- [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93] --> + <!-- --> + <!-- javaEncoding Java file encoding to use for generating java --> + <!-- source files. [UTF-8] --> + <!-- --> + <!-- keepgenerated Should we keep the generated Java source code --> + <!-- for each page instead of deleting it? [true] --> + <!-- --> + <!-- logVerbosityLevel The level of detailed messages to be produced --> + <!-- by this servlet. Increasing levels cause the --> + <!-- generation of more messages. Valid values are --> + <!-- FATAL, ERROR, WARNING, INFORMATION, and DEBUG. --> + <!-- [WARNING] --> + <!-- --> + <!-- mappedfile Should we generate static content with one --> + <!-- print statement per input line, to ease --> + <!-- debugging? [false] --> + <!-- --> + <!-- --> + <!-- reloading Should Jasper check for modified JSPs? [true] --> + <!-- --> + <!-- suppressSmap Should the generation of SMAP info for JSR45 --> + <!-- debugging be suppressed? [false] --> + <!-- --> + <!-- dumpSmap Should the SMAP info for JSR45 debugging be --> + <!-- dumped to a file? [false] --> + <!-- False if suppressSmap is true --> + <!-- --> + <!-- scratchdir What scratch directory should we use when --> + <!-- compiling JSP pages? [default work directory --> + <!-- for the current web application] --> + <!-- --> + <!-- tagpoolMaxSize The maximum tag handler pool size [5] --> + <!-- --> + <!-- xpoweredBy Determines whether X-Powered-By response --> + <!-- header is added by generated servlet [false] --> + <!-- --> + <!-- If you wish to use Jikes to compile JSP pages: --> + <!-- Set the init parameter "compiler" to "jikes". Define --> + <!-- the property "-Dbuild.compiler.emacs=true" when starting Jetty --> + <!-- to cause Jikes to emit error messages in a format compatible with --> + <!-- Jasper. --> + <!-- If you get an error reporting that jikes can't use UTF-8 encoding, --> + <!-- try setting the init parameter "javaEncoding" to "ISO-8859-1". --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <servlet id="jsp"> + <servlet-name>jsp</servlet-name> + <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> + <init-param> + <param-name>logVerbosityLevel</param-name> + <param-value>DEBUG</param-value> + </init-param> + <init-param> + <param-name>fork</param-name> + <param-value>false</param-value> + </init-param> + <init-param> + <param-name>xpoweredBy</param-name> + <param-value>false</param-value> + </init-param> + <init-param> + <param-name>development</param-name> + <param-value>true</param-value> + </init-param> + <init-param> + <param-name>modificationTestInterval</param-name> + <param-value>60</param-value> + </init-param> + <load-on-startup>0</load-on-startup> + </servlet> + + <servlet-mapping> + <servlet-name>jsp</servlet-name> + <url-pattern>*.jsp</url-pattern> + <url-pattern>*.jspf</url-pattern> + <url-pattern>*.jspx</url-pattern> + <url-pattern>*.xsp</url-pattern> + <url-pattern>*.JSP</url-pattern> + <url-pattern>*.JSPF</url-pattern> + <url-pattern>*.JSPX</url-pattern> + <url-pattern>*.XSP</url-pattern> + </servlet-mapping> + <!-- ==================================================================== --> + <!-- Dynamic Servlet Invoker. --> + <!-- This servlet invokes anonymous servlets that have not been defined --> + <!-- in the web.xml or by other means. The first element of the pathInfo --> + <!-- of a request passed to the envoker is treated as a servlet name for --> + <!-- an existing servlet, or as a class name of a new servlet. --> + <!-- This servlet is normally mapped to /servlet/* --> + <!-- This servlet support the following initParams: --> + <!-- --> + <!-- nonContextServlets If false, the invoker can only load --> + <!-- servlets from the contexts classloader. --> + <!-- This is false by default and setting this --> + <!-- to true may have security implications. --> + <!-- --> + <!-- verbose If true, log dynamic loads --> + <!-- --> + <!-- * All other parameters are copied to the --> + <!-- each dynamic servlet as init parameters --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- Uncomment for dynamic invocation + <servlet> + <servlet-name>invoker</servlet-name> + <servlet-class>org.mortbay.jetty.servlet.Invoker</servlet-class> + <init-param> + <param-name>verbose</param-name> + <param-value>false</param-value> + </init-param> + <init-param> + <param-name>nonContextServlets</param-name> + <param-value>false</param-value> + </init-param> + <init-param> + <param-name>dynamicParam</param-name> + <param-value>anyValue</param-value> + </init-param> + <load-on-startup>0</load-on-startup> + </servlet> + + <servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping> + --> + + + + <!-- ==================================================================== --> + <session-config> + <!-- FIXME: change to adjust when sessions are expunged --> + <session-timeout>30</session-timeout> + </session-config> + + <!-- ==================================================================== --> + <!-- Default MIME mappings --> + <!-- The default MIME mappings are provided by the mime.properties --> + <!-- resource in the org.mortbay.jetty.jar file. Additional or modified --> + <!-- mappings may be specified here --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- UNCOMMENT TO ACTIVATE + <mime-mapping> + <extension>mysuffix</extension> + <mime-type>mymime/type</mime-type> + </mime-mapping> + --> + + <!-- ==================================================================== --> + <welcome-file-list> + <welcome-file>index.html</welcome-file> + <welcome-file>index.htm</welcome-file> + <welcome-file>index.jsp</welcome-file> + </welcome-file-list> + + <!-- ==================================================================== --> + <locale-encoding-mapping-list> + <locale-encoding-mapping><locale>ar</locale><encoding>ISO-8859-6</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>be</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>bg</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>ca</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>cs</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>da</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>de</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>el</locale><encoding>ISO-8859-7</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>en</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>es</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>et</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>fi</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>fr</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>hr</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>hu</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>is</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>it</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>iw</locale><encoding>ISO-8859-8</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>ja</locale><encoding>Shift_JIS</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>ko</locale><encoding>EUC-KR</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>lt</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>lv</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>mk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>nl</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>no</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>pl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>pt</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>ro</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>ru</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>sh</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>sk</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>sl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>sq</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>sr</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>sv</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>tr</locale><encoding>ISO-8859-9</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>uk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>zh</locale><encoding>GB2312</encoding></locale-encoding-mapping> + <locale-encoding-mapping><locale>zh_TW</locale><encoding>Big5</encoding></locale-encoding-mapping> + </locale-encoding-mapping-list> + + <security-constraint> + <web-resource-collection> + <web-resource-name>Disable TRACE</web-resource-name> + <url-pattern>/</url-pattern> + <http-method>TRACE</http-method> + </web-resource-collection> + <auth-constraint/> + </security-constraint> + +</web-app> + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <al...@us...> - 2010-08-17 01:00:36
|
Revision: 531 http://virtualcommons.svn.sourceforge.net/virtualcommons/?rev=531&view=rev Author: alllee Date: 2010-08-17 01:00:30 +0000 (Tue, 17 Aug 2010) Log Message: ----------- changing jetty plugin to predictable 6.1.22 version instead Modified Paths: -------------- foraging/trunk/pom.xml Modified: foraging/trunk/pom.xml =================================================================== --- foraging/trunk/pom.xml 2010-08-17 00:33:56 UTC (rev 530) +++ foraging/trunk/pom.xml 2010-08-17 01:00:30 UTC (rev 531) @@ -121,8 +121,17 @@ </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> + <artifactId>maven-jetty-plugin</artifactId> + <version>6.1.22</version> <configuration> + <connectors> + <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector"> + <port>8080</port> + <maxIdleTime>60000</maxIdleTime> + </connector> + </connectors> + <contextPath>/</contextPath> + <webDefaultXml>src/main/resources/web/webdefault.xml</webDefaultXml> <scanIntervalSeconds>10</scanIntervalSeconds> </configuration> </plugin> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <al...@us...> - 2010-08-17 00:34:04
|
Revision: 530 http://virtualcommons.svn.sourceforge.net/virtualcommons/?rev=530&view=rev Author: alllee Date: 2010-08-17 00:33:56 +0000 (Tue, 17 Aug 2010) Log Message: ----------- removing copied / generated files. Should actually deploy elsewhere.. Removed Paths: ------------- foraging/trunk/src/main/webapp/client.jnlp foraging/trunk/src/main/webapp/facilitator.jnlp Deleted: foraging/trunk/src/main/webapp/client.jnlp =================================================================== --- foraging/trunk/src/main/webapp/client.jnlp 2010-08-17 00:08:01 UTC (rev 529) +++ foraging/trunk/src/main/webapp/client.jnlp 2010-08-17 00:33:56 UTC (rev 530) @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- JNLP file for foraging client --> -<jnlp spec="1.6+" codebase="http://localhost:8080" href="client.jnlp"> - <information> - <title>Virtual Commons Experiment</title> - <vendor>The Virtual Commons, Center for the Study of Institutional Diversity, School of Human Evolution and Social Change, Dr. Marco Janssen, Allen Lee, Deepali Bhagvat</vendor> - <homepage href="http://commons.asu.edu"/> - <description>An experiment brought to you courtesy of The Virtual Commons - http://commons.asu.edu</description> - </information> - <offline-allowed /> - <resources> - <j2se version="1.6+"/> - <jar href="client.jar"/> - <jar href='csidex.jar'/> - <property name="sun.java2d.noddraw" value="true"/> - <extension name="jogl" href="http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp"/> - </resources> - <application-desc main-class="edu.asu.commons.foraging.client.ForagingClient"/> -</jnlp> - Deleted: foraging/trunk/src/main/webapp/facilitator.jnlp =================================================================== --- foraging/trunk/src/main/webapp/facilitator.jnlp 2010-08-17 00:08:01 UTC (rev 529) +++ foraging/trunk/src/main/webapp/facilitator.jnlp 2010-08-17 00:33:56 UTC (rev 530) @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- JNLP File for CSAN 2D Facilitator --> -<jnlp spec="1.6+" codebase="http://localhost:8080" href="facilitator.jnlp"> - <information> - <title>Virtual Commons Experiment</title> - <vendor>The Virtual Commons, Center for the Study of Institutional Diversity, School of Human Evolution and Social Change, Dr. Marco Janssen, Allen Lee, Deepali Bhagvat</vendor> - <homepage href="http://commons.asu.edu"/> - <description>Foraging 2D facilitator interface to control the Foraging 2D experiment.</description> - <icon href="commons.gif"/> - </information> - <offline-allowed /> - <resources> - <j2se version="1.6+"/> - <jar href="facilitator.jar"/> - <jar href='csidex.jar'/> - </resources> - <application-desc main-class="edu.asu.commons.foraging.facilitator.Facilitator"/> -</jnlp> - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <al...@us...> - 2010-08-17 00:08:08
|
Revision: 529 http://virtualcommons.svn.sourceforge.net/virtualcommons/?rev=529&view=rev Author: alllee Date: 2010-08-17 00:08:01 +0000 (Tue, 17 Aug 2010) Log Message: ----------- Removing some dead code (looks like directly translated from C++?) from Deepali's 3D impl and refactored voting / regulation a bit, more refactoring anticipated. Modified Paths: -------------- foraging/trunk/src/main/java/edu/asu/commons/foraging/client/EnforcementPanel.java foraging/trunk/src/main/java/edu/asu/commons/foraging/client/ForagingClient.java foraging/trunk/src/main/java/edu/asu/commons/foraging/client/GameWindow2D.java foraging/trunk/src/main/java/edu/asu/commons/foraging/client/InstructionsView.java foraging/trunk/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java foraging/trunk/src/main/java/edu/asu/commons/foraging/conf/ServerConfiguration.java foraging/trunk/src/main/java/edu/asu/commons/foraging/facilitator/Facilitator.java foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/core/CoreModel.java foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/instance/Mixer.java foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/instance/Model.java foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/misc/Loader.java foraging/trunk/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java foraging/trunk/src/main/java/edu/asu/commons/foraging/util/MovieCreator.java Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/client/EnforcementPanel.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/client/EnforcementPanel.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/client/EnforcementPanel.java 2010-08-17 00:08:01 UTC (rev 529) @@ -13,7 +13,6 @@ import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextArea; -import javax.swing.ScrollPaneConstants; import edu.asu.commons.foraging.event.EnforcementRankingRequest; import edu.asu.commons.foraging.model.EnforcementMechanism; Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/client/ForagingClient.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/client/ForagingClient.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/client/ForagingClient.java 2010-08-17 00:08:01 UTC (rev 529) @@ -130,7 +130,7 @@ } @Override - @SuppressWarnings("unchecked") + @SuppressWarnings("rawtypes") protected void initializeEventProcessors() { addEventProcessor(new EventTypeProcessor<SetConfigurationEvent>(SetConfigurationEvent.class) { public void handle(SetConfigurationEvent event) { @@ -234,7 +234,7 @@ addEventProcessor(new EventTypeProcessor<ClientMessageEvent>(ClientMessageEvent.class) { public void handle(ClientMessageEvent event) { - gameWindow2D.displayErrorMessage(event.toString(),0); + gameWindow2D.displayMessage(event.toString()); } }); addEventProcessor(new EventTypeProcessor<EnforcementMechanismUpdateEvent>(EnforcementMechanismUpdateEvent.class) { Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/client/GameWindow2D.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/client/GameWindow2D.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/client/GameWindow2D.java 2010-08-17 00:08:01 UTC (rev 529) @@ -32,7 +32,6 @@ import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; -import javax.swing.JTextArea; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.Timer; @@ -56,7 +55,6 @@ import edu.asu.commons.foraging.event.QuizResponseEvent; import edu.asu.commons.foraging.event.RealTimeSanctionRequest; import edu.asu.commons.foraging.event.ResetTokenDistributionRequest; -import edu.asu.commons.foraging.event.SubmitRegulationRequest; import edu.asu.commons.foraging.model.ClientData; import edu.asu.commons.foraging.model.Direction; import edu.asu.commons.net.Identifier; @@ -376,39 +374,19 @@ } } - private void startRegulationSubmissionTimer() { - if (timer == null) { - duration = Duration.create(dataModel.getRoundConfiguration().getRegulationSubmissionDuration()); - timer = new Timer(1000, new ActionListener() { - public void actionPerformed(ActionEvent event) { - if (duration.hasExpired()) { - timeLeftLabel.setText("Time's up."); - timer.stop(); - timer = null; - String regulation = regulationTextArea.getText(); - client.transmit(new SubmitRegulationRequest(client.getId(), regulation)); - displayVotingWaitMessage(); - } - else { - timeLeftLabel.setText( String.format("You have %d second(s) left to write your regulation.", duration.getTimeLeft() / 1000L) ); - } - } - }); - timer.start(); - } - } private void startChatTimer() { if (timer == null) { - // final Duration duration = Duration.create(dataModel.getRoundConfiguration().getChatDuration()); - final Duration duration = Duration.create(dataModel.getRoundConfiguration().getChatDuration()); + final RoundConfiguration roundConfiguration = dataModel.getRoundConfiguration(); + final Duration duration = Duration.create(roundConfiguration.getChatDuration()); timer = new Timer(1000, new ActionListener() { public void actionPerformed(ActionEvent event) { if (duration.hasExpired()) { timeLeftLabel.setText("Chat is now disabled."); timer.stop(); timer = null; - initializeSanctionDecisionPanel(); - //initializeRegulationPanel(); + if (roundConfiguration.isVotingAndRegulationEnabled()) { + initializeSanctionDecisionPanel(); + } } else { timeLeftLabel.setText( String.format("Chat will end in %d seconds.", duration.getTimeLeft() / 1000L) ); @@ -518,19 +496,6 @@ informationLabel.setBackground(Color.YELLOW); informationLabel.setForeground(Color.BLUE); - // getSanctioningPanel().initializeVotingPaneWithRegulations(); - - // regulationVotingPane = new JPanel(); - // //regulationVotingPane.setLayout(new BoxLayout(regulationVotingPane, BoxLayout.LINE_AXIS)); - // regulationVotingPane.setLayout(new BorderLayout(4,4)); - // - // regulationVotingIntructions = new JEditorPane(); - // regulationVotingIntructions.setContentType("text/html"); - // regulationVotingIntructions.setEditorKit(new HTMLEditorKit()); - // regulationVotingIntructions.setEditable(false); - // regulationVotingIntructions.setBorder(BorderFactory.createTitledBorder("Regulation voting instructions")); - // regulationVotingIntructionsScrollPane = new JScrollPane(regulationVotingIntructions); - labelPanel = new JPanel(); labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.LINE_AXIS)); labelPanel.setBackground(Color.WHITE); @@ -612,7 +577,7 @@ event = new CollectTokenRequest(client.getId()); } else { - displayErrorMessage("You cannot harvest at this time.", 1); + displayErrorMessage("You cannot harvest at this time."); } break; // real-time sanctioning keycode handling @@ -621,7 +586,7 @@ case KeyEvent.VK_7: case KeyEvent.VK_8: case KeyEvent.VK_9: if (! dataModel.isSanctioningAllowed()) { // get rid of magic constants - displayErrorMessage("You aren't allowed to reduce other participants tokens at this time.", 1); + displayErrorMessage("You may not reduce other participants tokens at this time."); return; } if (client.canPerformRealTimeSanction()) { @@ -641,7 +606,7 @@ // dataModel.sanction(dataModel.getId(), sanctionee); } else { - displayErrorMessage("The participant is out of range ", 1); + displayErrorMessage("The participant is out of range."); return; } } @@ -723,12 +688,18 @@ }; SwingUtilities.invokeLater(runnable); } + + public void displayErrorMessage(String errorMessage) { + displayMessage(errorMessage, Color.RED); + } + + public void displayMessage(String message) { + displayMessage(message, Color.BLACK); + } - public void displayErrorMessage(String errorMessage, int par) { + public void displayMessage(String errorMessage, Color color) { // String chatHandle = getChatHandle(source); - if(par==1)errorMessageTextPane.setForeground(Color.RED); - else errorMessageTextPane.setForeground(Color.BLACK); - + errorMessageTextPane.setForeground(color); StyledDocument document = errorMessageTextPane.getStyledDocument(); try { document.insertString(document.getLength(), errorMessage + "\n", document.getStyle("bold")); @@ -1036,30 +1007,6 @@ startSanctionVotingTimer(); } - - public void initializeRegulationPanel() { - // getRegulationPanel().initialize(); - // System.out.println("Initialization done"); - addCenterComponent(getSubmitRegulationPanel()); - startRegulationSubmissionTimer(); - } - - private JPanel submitRegulationPanel; - private JTextArea regulationTextArea; - private JPanel getSubmitRegulationPanel() { - if (submitRegulationPanel == null) { - submitRegulationPanel = new JPanel(new BorderLayout()); - regulationTextArea = new JTextArea(); - submitRegulationPanel.add(regulationTextArea, BorderLayout.CENTER); - regulationTextArea.setBorder(BorderFactory.createTitledBorder("Type your regulation here")); - HtmlEditorPane editorPane = createInstructionsEditorPane(); - JScrollPane scrollPane = new JScrollPane(editorPane); - editorPane.setText(dataModel.getRoundConfiguration().getRegulationInstructions()); - submitRegulationPanel.add(scrollPane, BorderLayout.PAGE_START); - } - return submitRegulationPanel; - } - private JPanel decisionPanel; private ButtonGroup group; private JRadioButton sanction; Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/client/InstructionsView.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/client/InstructionsView.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/client/InstructionsView.java 2010-08-17 00:08:01 UTC (rev 529) @@ -66,15 +66,19 @@ if (roundConfiguration.isPracticeRound()) { instructionsBuilder.append("<h3>Note - since this was a practice round you did not earn any income this round.</h3>"); } - double showUpFee = roundConfiguration.getParentConfiguration().getShowUpPayment(); + double showUpPayment = roundConfiguration.getParentConfiguration().getShowUpPayment(); instructionsBuilder.append(String.format("Your <b>total income</b> so far (including a $%3.2f bonus for showing up) is : $%3.2f<hr>", - showUpFee, dataModel.getTotalIncome() + showUpFee)); + showUpPayment, dataModel.getTotalIncome() + showUpPayment)); if (lastRound) { instructionsBuilder.append(roundConfiguration.getLastRoundDebriefing()); } setInstructions(instructionsBuilder.toString()); } + /** + * Only used by {@link GameWindow3D} at the moment. + * @param instructions + */ public void appendInstructions(String instructions) { instructionsBuilder.append(instructions); setInstructions(instructionsBuilder.toString()); Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java 2010-08-17 00:08:01 UTC (rev 529) @@ -417,10 +417,6 @@ return ! isPrivateProperty() && getBooleanProperty("chat-enabled"); } - public boolean isVotingEnabled() { - return getBooleanProperty("voting-enabled", false); - } - public int getMaximumResourceAge() { return getIntProperty("maximum-resource-age", 10); } @@ -499,6 +495,10 @@ return EnforcementMechanism.values(); } + public boolean isRotatingMonitorEnabled() { + return getBooleanProperty("rotating-monitor-enabled", false); + } + public boolean isVotingAndRegulationEnabled() { return getBooleanProperty("voting-and-regulation-enabled", false); } @@ -528,6 +528,19 @@ return buildInstructions(new StringBuilder()); } + /** + * The preferred method of building instructions within the foraging experiment. + * + * Given a StringBuilder, will append the various instructions conditionally relevant + * to this {@link #RoundConfiguration()}. + * + * For example, if the field of vision is enabled, will append the field of vision instructions, + * if censored chat is enabled, then it will aadd the censored chat instructions, if the + * chat is enabled, will append the chat instructions. + * + * @param instructionsBuilder + * @return + */ public StringBuilder buildInstructions(StringBuilder instructionsBuilder) { if (isFirstRound()) { instructionsBuilder.append(getGeneralInstructions()); @@ -536,17 +549,24 @@ if (isFieldOfVisionEnabled()) { // create note type box, test to see how // JEditorPaneS render CSS divs or fieldsets..? - instructionsBuilder.append("<hr>"); - instructionsBuilder.append(getFieldOfVisionInstructions()); + instructionsBuilder.append("<hr><b>"); + instructionsBuilder.append(getFieldOfVisionInstructions()).append("</b>"); } if (isChatEnabled()) { - instructionsBuilder.append("<hr>"); - instructionsBuilder.append("Before the beginning of this round you will be able to chat with the other members of your group for ").append(getChatDuration()).append(" seconds."); + instructionsBuilder.append("<hr><b>"); + // FIXME: hard-coded, need to make instructions template-able, perhaps + // via FreeMarker or Velocity. + instructionsBuilder.append("Before the beginning of this round you will be able to chat with the other members of your group for ").append(getChatDuration()).append(" seconds.</b>"); } + if (isCensoredChat()) { + instructionsBuilder.append("<hr><b>"); + instructionsBuilder.append(getCensoredChatInstructions()).append("</b>"); + } + // and add the quiz instructions if the quiz is enabled. if (isQuizEnabled()) { - instructionsBuilder.append("<hr>"); - instructionsBuilder.append(getQuizInstructions()); + instructionsBuilder.append("<hr><b>"); + instructionsBuilder.append(getQuizInstructions()).append("</b>"); } return instructionsBuilder; Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/conf/ServerConfiguration.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/conf/ServerConfiguration.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/conf/ServerConfiguration.java 2010-08-17 00:08:01 UTC (rev 529) @@ -23,7 +23,7 @@ private static final long serialVersionUID = -1737412253553943902L; - private final static String DEFAULT_LOG_FILE_DESTINATION = "csan-server.log"; + private final static String DEFAULT_LOG_FILE_DESTINATION = "foraging-server.log"; public ServerConfiguration() { super(); Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/facilitator/Facilitator.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/facilitator/Facilitator.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/facilitator/Facilitator.java 2010-08-17 00:08:01 UTC (rev 529) @@ -46,7 +46,8 @@ private Facilitator() { this(new ServerConfiguration()); } - + + @SuppressWarnings("rawtypes") public Facilitator(ServerConfiguration configuration) { super(configuration); addEventProcessor(new EventTypeProcessor<SetConfigurationEvent>(SetConfigurationEvent.class) { Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/core/CoreModel.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/core/CoreModel.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/core/CoreModel.java 2010-08-17 00:08:01 UTC (rev 529) @@ -174,10 +174,10 @@ */ public int createCoreMaterial(Color color) { CoreMaterial coreMaterial = new CoreMaterial(); - if(coreMaterial == null) { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return -1; - } +// if(coreMaterial == null) { +// Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); +// return -1; +// } setCoreMaterial(coreMaterial, color); return addCoreMaterial(coreMaterial); } Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/instance/Mixer.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/instance/Mixer.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/instance/Mixer.java 2010-08-17 00:08:01 UTC (rev 529) @@ -102,11 +102,6 @@ // allocate a new animation cycle instance AnimationCycle animationCycle = new AnimationCycle(coreAnimation); - if(animationCycle == null) { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return false; - } - // insert new animation into the tables animations.setElementAt(animationCycle, id); animationCycleList.addFirst(animationCycle); @@ -210,11 +205,6 @@ // allocate a new animation action instance AnimationAction animationAction = new AnimationAction(coreAnimation); - if(animationAction == null) { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return false; - } - // insert new animation into the table animationActionList.add(animationAction); Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/instance/Model.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/instance/Model.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/instance/Model.java 2010-08-17 00:08:01 UTC (rev 529) @@ -76,11 +76,6 @@ // allocate a new mesh instance Mesh mesh = new Mesh(coreMesh); - if(mesh == null) { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return false; - } - // set model in the mesh instance mesh.setModel(this); Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/misc/Loader.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/misc/Loader.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/jcal3d/misc/Loader.java 2010-08-17 00:08:01 UTC (rev 529) @@ -134,11 +134,11 @@ //Allocate a new core skeleton instance CoreSkeleton coreSkeleton = new CoreSkeleton(); - if(coreSkeleton == null) - { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return null; - } +// if(coreSkeleton == null) +// { +// Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); +// return null; +// } //Load all core bones for(int boneIndex = 0; boneIndex < boneCount; ++boneIndex) { @@ -237,11 +237,10 @@ // // allocate a new core bone instance CoreBone coreBone = new CoreBone(boneName); - if(coreBone == null) - { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return null; - } +// if(coreBone == null) { +// Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); +// return null; +// } // set the parent of the bone coreBone.setParentId(parentId); @@ -337,10 +336,10 @@ // allocate a new core animation instance CoreAnimation coreAnimation = new CoreAnimation(); - if(coreAnimation == null) { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return null; - } +// if(coreAnimation == null) { +// Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); +// return null; +// } // get the duration of the core animation float duration = inputBuffer.getFloat(); @@ -390,11 +389,6 @@ // allocate a new core track instance CoreTrack coreTrack = new CoreTrack(); - if(coreTrack == null) { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return null; - } - // link the core track to the appropriate core bone instance coreTrack.setCoreBoneId(coreBoneId); @@ -454,11 +448,6 @@ // allocate a new core keyframe instance CoreKeyframe coreKeyframe = new CoreKeyframe(); - if(coreKeyframe == null) { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return null; - } - // set all attributes of the keyframe coreKeyframe.setTime(time); coreKeyframe.setTranslation(new Vector3D(tx, ty, tz)); @@ -519,11 +508,6 @@ int submeshCount = inputBuffer.getInt(); // allocate a new core mesh instance CoreMesh coreMesh = new CoreMesh(); - if(coreMesh == null) { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return null; - } - // load all core submeshes for(int submeshId = 0; submeshId < submeshCount; ++submeshId) { // load the core submesh @@ -559,11 +543,6 @@ // allocate a new core submesh instance CoreSubmesh coreSubmesh = new CoreSubmesh(); - if(coreSubmesh == null) { - Error.setLastError(Error.MEMORY_ALLOCATION_FAILED, "", -1, ""); - return null; - } - // set the LOD step count coreSubmesh.setLodCount(lodCount); Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java 2010-08-17 00:08:01 UTC (rev 529) @@ -487,6 +487,7 @@ } } + // FIXME: get rid of sanction ranking in favor of enforcement mechanism update private void sendSanctionRankingUpdate(GroupDataModel group) { group.generateSanctionRankings(); for (Identifier id: group.getClientIdentifiers()) { @@ -844,13 +845,15 @@ private void processRound2d() { boolean secondHasPassed = secondTick.hasExpired(); if (secondHasPassed) { - if (getCurrentRoundConfiguration().isVotingAndRegulationEnabled() + // handle rotating monitors. + if (getCurrentRoundConfiguration().isRotatingMonitorEnabled() && currentRoundDuration.getElapsedTimeInSeconds() % monitorRotationInterval == 0) { for (GroupDataModel group: serverDataModel.getGroups()) { boolean rotated = group.rotateMonitorIfNecessary(); if (rotated) { // send new roles to all clients + // FIXME: this is inefficient, we could synchronize twice. for (ClientData clientData : group.getClientDataMap().values()) { transmit(new SynchronizeClientEvent(clientData, currentRoundDuration.getTimeLeft())); } Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/util/MovieCreator.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/util/MovieCreator.java 2010-08-16 23:05:49 UTC (rev 528) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/util/MovieCreator.java 2010-08-17 00:08:01 UTC (rev 529) @@ -342,7 +342,7 @@ */ static MediaLocator createMediaLocator(String url) { - MediaLocator ml; + MediaLocator ml = null; if (url.indexOf(":") > 0 && (ml = new MediaLocator(url)) != null) return ml; @@ -350,14 +350,15 @@ if (url.startsWith(File.separator)) { if ((ml = new MediaLocator("file:" + url)) != null) return ml; - } else { + } + else { String file = "file:" + System.getProperty("user.dir") + File.separator + url; - if ((ml = new MediaLocator(file)) != null) + if ((ml = new MediaLocator(file)) != null) { return ml; + } } - - return null; + return ml; } // ///////////////////////////////////////////// This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <al...@us...> - 2010-08-16 23:05:56
|
Revision: 528 http://virtualcommons.svn.sourceforge.net/virtualcommons/?rev=528&view=rev Author: alllee Date: 2010-08-16 23:05:49 +0000 (Mon, 16 Aug 2010) Log Message: ----------- initial version of censored chat configuration files for experiments at Stockholm. Continued interface improvements are anticipated for the facilitator. Added Paths: ----------- foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/ foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round0.xml foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round1.xml foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round2.xml foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round3.xml foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round4.xml foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round5.xml foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round6.xml foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/server.xml Added: foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round0.xml =================================================================== --- foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round0.xml (rev 0) +++ foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round0.xml 2010-08-16 23:05:49 UTC (rev 528) @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>Foraging XML-ized experiment round configuration</comment> +<entry key="resource-width">13</entry> +<entry key="resource-depth">13</entry> +<entry key="practice-round">true</entry> +<entry key="private-property">true</entry> +<entry key="duration">240</entry> + +<entry key='tokens-field-of-vision'>true</entry> +<entry key='subjects-field-of-vision'>true</entry> + +<entry key="quiz">true</entry> +<entry key="q1">C</entry> +<entry key="q2">B</entry> + +<entry key='instructions'> +<![CDATA[ +<h3>Practice Round Instructions</h3> +<hr> +<p> +You will now have four minutes to practice with the experimental environment. +The decisions you make in this round will NOT influence your earnings. At the +At the beginning of the practice round half of the cells are occupied +with green tokens. The environment is a 13 x 13 grid of cells. +</p> +<p> +During this practice round, and <b>only during</b> this practice round, you are able +to reset the tokens displayed on the screen by pressing the <b>R</b> key. When you +press the <b>R</b> key you will reset the resource to its initial distribution, +randomly filling half of the cells. +</p> +<p><b> Please do not communicate with any other participant.</b></p> +<p>If you have any questions please raise your hand. <b>Do you have any +questions so far?</b></p> +]]> +</entry> + +<entry key="quiz-instructions"> +<![CDATA[ +<p> +Before we begin the practice round you need to answer the following questions +correctly. You can only continue when you have answered all questions +correctly. If an error is made you will need to answer the questions again. +</p> +<br> +<form> +<span class='q1'>Q1. Which of the statements is <b><u>incorrect</u></b>?</span> <br> +<input type="radio" name="q1" value="A">A. Your decisions of where to collect tokens affects the regeneration of tokens.<br> +<input type="radio" name="q1" value="B">B. When you have collected all tokens on the screen, no new tokens will appear.<br> +<input type="radio" name="q1" value="C">C. Tokens grow from the middle of the +screen.<br> +<input type="radio" name="q1" value="D">D. In order to collect a token you need +to press the space bar while your yellow dot <img src="@CODEBASE_URL@/images/gem-self.gif"> is on a cell with a token.<br> +<br><br> + +<span class='q2'>Q2. Which sequence of situations is <b><u>not possible</u></b>?</span> <br> +<img src="@CODEBASE_URL@/images/question2.jpg"><br> +<input type="radio" name="q2" value="A">A<br> +<input type="radio" name="q2" value="B">B<br> +<input type="radio" name="q2" value="C">C<br> +<br> +<input type="submit" name="submit" value="Submit"> +</form> +]]> +</entry> + +</properties> Added: foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round1.xml =================================================================== --- foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round1.xml (rev 0) +++ foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round1.xml 2010-08-16 23:05:49 UTC (rev 528) @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>Foraging XML experiment round configuration</comment> +<entry key="display-group-tokens">true</entry> +<entry key="clients-per-group">5</entry> +<entry key="duration">240</entry> +<entry key="resource-depth">29</entry> +<entry key="resource-width">29</entry> + +<entry key='tokens-field-of-vision'>true</entry> +<entry key='subjects-field-of-vision'>true</entry> + +<entry key='always-explicit'>true</entry> +<entry key='max-cell-occupancy'>1</entry> + +<entry key='censored-chat-enabled'>true</entry> +<entry key='chat-enabled'>true</entry> + +<entry key="chat-instructions"> +<![CDATA[ +<p> +You can now chat with the other participants in your group for 4 minutes +total. During the chat round, you may communicate about any aspect of the +experiment that you would like to discuss with other participants with whom +you have been matched. You may not promise them side-payments after the +experiment is completed or threaten them with any consequence after the +experiment is finished. We are monitoring the chat traffic while you chat. If we +detect any violation of these rules, we will stop the experiment and remove the +offending group from the room. +</p> +<p> +You will see other participants labeled as "1", "2","3", "4", or "5" in the +chat box. You can send a chat message by typing into the textfield at the +bottom of the screen and pressing the "enter" key on your keyboard. +</p> +]]> +</entry> + +<entry key='censored-chat-instructions'> +<![CDATA[ +<p> +Your messages must first be approved by our censor before they will be relayed to the rest of your group. +</p> +]]> +</entry> + +<entry key="instructions"> +<![CDATA[ +<h3>Round 1 Instructions</h3> +<hr> +<p> +This is the first round of the experiment. The length of the round is 4 +minutes. As in the practice round you can collect green tokens but now +you will earn <b>two cents</b> for each token collected. You <b>cannot</b> +reset the distribution of green tokens. +</p> +<p> +In this round the renewable resource will become five times bigger. You will share this +larger environment with four other players in this room that have been randomly +selected. Each group's resource environment is distinct from the other groups. +</p> +<p> +Each of you has been assigned a number from 1 to 5. These numbers will remain the +same throughout the experiment but you will <b>not</b> be able to identify which +person in the room has been assigned which number, so your anonymity is guaranteed. +</p> + +<p> +The other four players will appear on the screen as blue dots +<img src="@CODEBASE_URL@/images/gem-other.gif"> with a white +number embedded in the dot. On the top right corner of the screen you can see +how many tokens each player has collected. On the top left corner of the screen you can see +a clock that displays the remaining time in the round.</p> +<p>Since you can only see the resource within your vision you may neither see all +the other participants nor all the resource units. The figure below indicates the +vision range compared to the whole environment</p> +<img src="@CODEBASE_URL@/images/vision-range.jpg"> +<p> +If you have any questions please raise your hand. <b>Do you have any +questions so far?</b> +</p> +]]> +</entry> +</properties> Added: foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round2.xml =================================================================== --- foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round2.xml (rev 0) +++ foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round2.xml 2010-08-16 23:05:49 UTC (rev 528) @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>Foraging XML-ized experiment round configuration</comment> +<entry key="display-group-tokens">true</entry> +<entry key="clients-per-group">5</entry> +<entry key="duration">240</entry> +<entry key="resource-depth">29</entry> +<entry key="resource-width">29</entry> + +<entry key='censored-chat-enabled'>true</entry> +<entry key='chat-enabled'>true</entry> + +<!-- enable field of vision for tokens and subjects --> +<entry key='initial-distribution'>.25</entry> + +<entry key='tokens-field-of-vision'>true</entry> +<entry key='subjects-field-of-vision'>true</entry> + +<entry key='always-explicit'>true</entry> +<entry key='max-cell-occupancy'>1</entry> + +<entry key="instructions"> +<![CDATA[ +<h3>Round 2 Instructions</h3> +<hr> +<p> +Round 2 is the same as round 1. +</p> +<p> +If you have any questions please raise your hand. <b>Do you have any +questions so far?</b> +</p> +]]> +</entry> +</properties> Added: foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round3.xml =================================================================== --- foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round3.xml (rev 0) +++ foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round3.xml 2010-08-16 23:05:49 UTC (rev 528) @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>Foraging XML-ized experiment round configuration</comment> +<entry key="display-group-tokens">true</entry> +<entry key="clients-per-group">5</entry> +<entry key="duration">240</entry> +<entry key="resource-depth">29</entry> +<entry key="resource-width">29</entry> + +<!-- enable field of vision for tokens and subjects --> +<entry key='tokens-field-of-vision'>true</entry> +<entry key='subjects-field-of-vision'>true</entry> + +<entry key='always-explicit'>true</entry> +<entry key='max-cell-occupancy'>1</entry> + +<entry key='censored-chat-enabled'>true</entry> +<entry key='chat-enabled'>true</entry> + +<!-- resource regrowth parameters --> +<entry key="initial-distribution">.25</entry> + +<entry key="instructions"> +<![CDATA[ +<h3>Round 3 Instructions</h3> +<hr> +<p> +Round 3 is the same as round 2. +</p> +<p> +If you have any questions please raise your hand. <b>Do you have any +questions so far?</b> +</p> +]]> +</entry> +</properties> Added: foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round4.xml =================================================================== --- foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round4.xml (rev 0) +++ foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round4.xml 2010-08-16 23:05:49 UTC (rev 528) @@ -0,0 +1,155 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>Foraging XML-ized experiment round configuration</comment> +<entry key="display-group-tokens">true</entry> +<entry key="clients-per-group">5</entry> +<entry key="resource-depth">29</entry> +<entry key="resource-width">29</entry> +<entry key="duration">240</entry> + +<!-- enable field of vision for tokens and subjects --> +<entry key='tokens-field-of-vision'>true</entry> +<entry key='subjects-field-of-vision'>true</entry> + +<entry key='always-explicit'>true</entry> +<entry key='max-cell-occupancy'>1</entry> + +<!-- before this round begins, we have a chat session --> +<entry key="chat-enabled">true</entry> + +<entry key='censored-chat-enabled'>true</entry> +<entry key='chat-enabled'>true</entry> + +<!-- enable sanctioning --> +<entry key="sanction-type">real-time</entry> +<entry key="sanction-cost">1</entry> +<entry key="sanction-multiplier">2</entry> + + +<entry key="initial-distribution">.25</entry> + +<!-- enable quiz --> +<entry key='quiz'>true</entry> +<entry key='q1'>B</entry> +<entry key='q2'>C</entry> +<entry key='q3'>B</entry> +<entry key='q4'>B</entry> + +<entry key="instructions"> +<![CDATA[ +<h3>Round 4 Instructions</h3> +<hr> +<p> +Round 4 is the same as the previous two rounds with two exceptions. +</p> +<p> +Before the next round starts you can anonymously communicate by text messages +for four minutes with the other participants in your group. You can use this +opportunity to discuss the experiment and coordinate your actions to improve +your earnings. You may not promise side-payments after the experiment is +completed or make any threats. You are also not allowed to reveal your real +identity. We are monitoring the chat traffic while you chat. +</p> +<p> +During the next round you will have the option to reduce the earnings of another +participant at a cost to your own earnings. +</p> +<ul> +<li>If you press the numeric key 1-5 corresponding to another participant, you +will reduce the number of tokens they have collected in this round by two +tokens. This will also reduce your own token amount by one token. The decision +whether or when to use this option is up to you. +<li>When you reduce the number of tokens of another participant, they will +receive a message stating that you have reduced their tokens. Likewise, if +another participant reduces your number of tokens, you will also receive a +message. These messages will be displayed on the bottom of your screen. +<li>If your tokens are being reduced or you are reducing another participant's +tokens, you will receive some visual cues. When you are sanctioned your yellow dot will turn red briefly with a blue background. The participant sanctioning you will turn purple with a white background. +<li>You may sanction other participants as long as there are +tokens remaining on the screen and while both you and the other participant +have a positive number of tokens collected during the round. <b>Each time</b> +you press the numeric key corresponding to another participant your token +amount is reduced by <b>one</b>, and their token amount is reduced by +<b>two</b>. <b>Note:</b> You can only remove tokens from a participant that is +visible to you. +</ul> +<p> + +<p> +The length of this round is four minutes. +</p> +<p> +If you have any questions please raise your hand. <b>Do you have any +questions so far?</b> +</p> +]]> +</entry> + +<entry key="chat-instructions"> +<![CDATA[ +<p> +You can now chat with the other participants in your group for 4 minutes +total. During the chat round, you may communicate about any aspect of the +experiment that you would like to discuss with other participants with whom +you have been matched. You may not promise them side-payments after the +experiment is completed or threaten them with any consequence after the +experiment is finished. We are monitoring the chat traffic while you chat. If +we see that somebody reveals his or her identity, we have to stop the +experiment and remove the whole group from which this person is a member out +of this room. +</p> +<p> +You will see other participants labeled as "1", "2","3", "4", or "5" in the +chat box. You can send a chat message by typing into the textfield at the +bottom of the screen and pressing the "enter" key on your keyboard. +</p> +]]> +</entry> +<entry key="quiz-instructions"> +<![CDATA[ +<p>Before the next round begins you must complete the quiz below. You can +only continue when you have answered all questions correctly. If an error is +made you will need to answer the questions again. +</p> + +<form> +<span class='q1'>Q1. Each time I press the numeric keys between 1-5 my tokens will be reduced +by:</span><br> +<input type="radio" name="q1" value="A">A. 0 tokens<br> +<input type="radio" name="q1" value="B">B. 1 token<br> +<input type="radio" name="q1" value="C">C. 2 tokens<br> +<input type="radio" name="q1" value="D">D. 4 tokens<br> +<br><br> + +<span class='q2'>Q2. Each time I press the numeric keys between 1-5 the number of tokens of the +corresponding participant is reduced by:</span><br> +<input type="radio" name="q2" value="A">A. 0 tokens<br> +<input type="radio" name="q2" value="B">B. 1 token<br> +<input type="radio" name="q2" value="C">C. 2 tokens<br> +<input type="radio" name="q2" value="D">D. 4 tokens<br> +<br><br> + +<span class='q3'>Q3. The background of your yellow dot <img src="@CODEBASE_URL@/images/gem-self.gif"> turns blue. What does this represent?</span><br> +<input type="radio" name="q3" value="A">A. You collected a token<br> +<input type="radio" name="q3" value="B">B. Another participant is subtracting two +tokens from you<br> +<input type="radio" name="q3" value="C">C. You are subtracting two tokens from another +participant<br> +<input type="radio" name="q3" value="D">D. You are moving too fast<br> +<br><br> + +<span class='q4'>Q4. Every time I press the numeric keys between 1-5:</span><br> +<input type="radio" name="q4" value="A">A. Two tokens are subtracted from my tokens +collected this round<br> +<input type="radio" name="q4" value="B">B. One token is subtracted from my tokens +collected this round<br> +<input type="radio" name="q4" value="C">C. The background of my yellow dot <img src="@CODEBASE_URL@/images/gem-self.gif"> turns blue +momentarily<br> +<input type="radio" name="q4" value="D">D. My yellow dot <img src="@CODEBASE_URL@/images/gem-self.gif"> is paused for two seconds<br> + +<input type="submit" name="submit" value="Submit"> +</form> +]]> +</entry> +</properties> Added: foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round5.xml =================================================================== --- foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round5.xml (rev 0) +++ foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round5.xml 2010-08-16 23:05:49 UTC (rev 528) @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>Foraging XML-ized experiment round configuration</comment> +<entry key="display-group-tokens">true</entry> +<entry key="clients-per-group">5</entry> +<entry key="resource-depth">29</entry> +<entry key="resource-width">29</entry> +<entry key="duration">240</entry> + +<!-- enable field of vision for tokens and subjects --> +<entry key='tokens-field-of-vision'>true</entry> +<entry key='subjects-field-of-vision'>true</entry> + +<!-- enable sanctioning --> +<entry key="sanction-type">real-time</entry> +<entry key="sanction-cost">1</entry> +<entry key="sanction-multiplier">2</entry> + +<entry key="initial-distribution">.25</entry> + +<entry key='always-explicit'>true</entry> +<entry key='max-cell-occupancy'>1</entry> + +<entry key='censored-chat-enabled'>true</entry> +<entry key='chat-enabled'>true</entry> + +<!-- before this round begins, we have a chat session --> +<entry key="chat-enabled">true</entry> + +<entry key="instructions"> +<![CDATA[ +<h3>Round 5 Instructions</h3> +<hr> +<p> +Round 5 is the same as round 4.</p> +<p> +The length of this round is again four minutes. +</p> +<p> +If you have any questions please raise your hand. <b>Do you have any +questions so far?</b> +</p> +]]> +</entry> + +<entry key="chat-instructions"> +<![CDATA[ +<p> +You can now chat with the other participants in your group for 4 minutes +total. During the chat round, you may communicate about any aspect of the +experiment that you would like to discuss with other participants with whom +you have been matched. You may not promise them side-payments after the +experiment is completed or threaten them with any consequence after the +experiment is finished. We are monitoring the chat traffic while you chat. If +we see that somebody reveals his or her identity, we have to stop the +experiment and remove the whole group from which this person is a member out +of this room. +</p> +<p> +You will see other participants labeled as "1", "2","3", "4", or "5" in the +chat box. You can send a chat message by typing into the textfield at the +bottom of the screen and pressing the "enter" key on your keyboard. +</p> +]]> +</entry> + +<entry key='private-chat-instructions'> +<![CDATA[ +You may send private messages to a specific participant by clicking on the +appropriately labeled button (1, 2, 3, 4, or 5) before typing your message in +the chat box and sending it. By default you are communicating with all +members of your group. +]]> +</entry> + +</properties> Added: foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round6.xml =================================================================== --- foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round6.xml (rev 0) +++ foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/round6.xml 2010-08-16 23:05:49 UTC (rev 528) @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>Foraging XML-ized experiment round configuration</comment> +<entry key="display-group-tokens">true</entry> +<entry key="clients-per-group">5</entry> +<entry key="resource-depth">29</entry> +<entry key="resource-width">29</entry> +<entry key="duration">240</entry> + +<entry key='tokens-field-of-vision'>true</entry> +<entry key='subjects-field-of-vision'>true</entry> +<!-- enable sanctioning --> +<entry key="sanction-type">real-time</entry> +<entry key="sanction-cost">1</entry> +<entry key="sanction-multiplier">2</entry> + +<entry key="initial-distribution">.25</entry> + +<entry key='always-explicit'>true</entry> +<entry key='max-cell-occupancy'>1</entry> + +<!-- before this round begins, we have a chat session --> +<entry key="chat-enabled">true</entry> + +<entry key='censored-chat-enabled'>true</entry> +<entry key='chat-enabled'>true</entry> + +<entry key="instructions"> +<![CDATA[ +<h3>Round 6 Instructions</h3> +<hr> +<p> +Round 6 is the same as round 5.</p> +<p> +The length of this round is again four minutes. +</p> +<p> +If you have any questions please raise your hand. <b>Do you have any +questions so far?</b> +</p> +]]> +</entry> + +<entry key="last-round-debriefing"> +<![CDATA[ +<p> +This was the last round, but not the end of the experiment. We will now +determine your payments. While we are doing this, we request that you +carefully fill out a brief survey. +</p> +<p> +When we are ready we will call you one by one to the room next door. We will +pay you there in private. Please wait until your computer number is called, +and then proceed to the room next door to turn in your computer number and +your survey. +</p> +<p> +Please answer the survey carefully and thank you for participating. +</p> +]]> +</entry> + +<entry key="chat-instructions"> +<![CDATA[ +<p> +You can now chat with the other participants in your group for 4 minutes +total. During the chat round, you may communicate about any aspect of the +experiment that you would like to discuss with other participants with whom +you have been matched. You may not promise them side-payments after the +experiment is completed or threaten them with any consequence after the +experiment is finished. We are monitoring the chat traffic while you chat. If +we detect that somebody has revealed their identity, we will have to stop the +experiment and remove that person's entire group from the experiment. +</p> +<p> +You will see other participants labeled as "1", "2","3", "4", or "5" in the +chat box. You can send a chat message by typing into the textfield at the +bottom of the screen and pressing the "enter" key. </p> +]]> +</entry> +</properties> Added: foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/server.xml =================================================================== --- foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/server.xml (rev 0) +++ foraging/trunk/src/main/resources/configuration/asu-experiments/censored-chat/server.xml 2010-08-16 23:05:49 UTC (rev 528) @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>Costly Sanctioning XML-ized experiment round configuration</comment> +<entry key="hostname">@SERVER_ADDRESS@</entry> +<entry key="port">@PORT_NUMBER@</entry> +<entry key="round0">round0.xml</entry> +<entry key="round1">round1.xml</entry> +<entry key="round2">round2.xml</entry> +<entry key="round3">round3.xml</entry> +<entry key="round4">round4.xml</entry> +<entry key="round5">round5.xml</entry> +<entry key="round6">round6.xml</entry> +<entry key="wait-for-participants">true</entry> +<entry key="number-of-rounds">7</entry> +<entry key="facilitator-instructions"> +<![CDATA[ +<h3>Facilitator Instructions</h3> +<p> +Welcome to the facilitator interface. This interface allows you to control +the experiment. You may only modify configuration parameters <b>before</b> +you start the experiment by selecting the Configuration menu. When all the +participants are ready to begin the experiment, you can start the experiment +by selecting Experiment -> Start. After a round has been completed you +will be able to view the statistics for all of the participants. You can +begin the next round by selecting Round -> Start. +</p> +]]> +</entry> + +<entry key='field-of-vision-instructions'> +<![CDATA[ +Your vision is limited in this experiment. The area that is visible to you will be +shaded. +]]> +</entry> + +<entry key="welcome-instructions"> +<![CDATA[ +<h3>Welcome to the experiment. The experiment will begin shortly after everyone has been +assigned a station.</h3> +<p> +Please <b>wait quietly</b> and <b>do not close this window or open any other applications</b>. +</p> +]]> +</entry> + +<entry key="general-instructions"> +<![CDATA[ +<h3>General Instructions</h3> +<p> +Welcome. You have already earned 5 dollars by showing up at this experiment. You can +earn more, up to a maximum of 40 dollars, by participating in this experiment, which +will take about an hour to an hour and a half. The amount of money you earn depends +on your decisions as well as the decisions of other people in this room during the +six rounds of the experiment. +</p> +<p> +You appear on the screen as a yellow dot <img src="@CODEBASE_URL@/images/gem-self.gif">. +You move by pressing the four arrow keys on your keyboard. You can move up, down, +left, or right. You have to press a key for each and every move of your yellow dot. +In this experiment you can collect green diamond shaped tokens +<img src="@CODEBASE_URL@/images/gem-token.gif"> and earn two cents for each collected token. +To collect a token, move your yellow dot over a green token and press the <b>space +bar</b>. If you move over a token without pressing the <b>space bar</> you do NOT +collect that token. +</p> + +<p> +The tokens that you collect have the potential to regenerate. After you have +collected a green token, a new token can re-appear on that empty cell. +However, the rate at which new tokens will appear depends on the number of +adjacent cells with tokens. The more tokens in the eight cells around +an empty cell, the faster a new token will appear on that empty cell. In other +words, <b>existing tokens can generate new tokens</b>. To illustrate this, please +refer to Image 1 and Image 2. The middle cell in Image 1 denoted with an X has +a greater chance of regeneration than the middle cell in Image 2. When all +neighboring cells are empty, there is <b>no chance for regeneration</b>. + +<table width="100%"> +<tr> +<td align="center"><b>Image 1</b></td> +<td align="center"><b>Image 2</b></td> +</tr> +<tr> +<td align="center"> +<img src="@CODEBASE_URL@/images/8neighbors.jpg" alt="image 1"> +</td> +<td align="center"> +<img src="@CODEBASE_URL@/images/5neighbors.jpg" alt="image 2"> +</td> +</tr> +</table> +]]> +</entry> + + +</properties> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <al...@us...> - 2010-08-06 01:26:05
|
Revision: 527 http://virtualcommons.svn.sourceforge.net/virtualcommons/?rev=527&view=rev Author: alllee Date: 2010-08-06 01:25:58 +0000 (Fri, 06 Aug 2010) Log Message: ----------- updating ant data conversion task Modified Paths: -------------- foraging/trunk/build.xml Modified: foraging/trunk/build.xml =================================================================== --- foraging/trunk/build.xml 2010-08-06 01:25:27 UTC (rev 526) +++ foraging/trunk/build.xml 2010-08-06 01:25:58 UTC (rev 527) @@ -335,7 +335,7 @@ </junit> </target> - <property name='savefile.converter.class' value='edu.asu.commons.foraging.util.ForagingSaveFileConverter'/> + <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'/> <target name='convert' depends='compile'> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <al...@us...> - 2010-08-06 01:25:35
|
Revision: 526 http://virtualcommons.svn.sourceforge.net/virtualcommons/?rev=526&view=rev Author: alllee Date: 2010-08-06 01:25:27 +0000 (Fri, 06 Aug 2010) Log Message: ----------- moving save file conversion to foraging.data package, extracting save file processors into separate classes since ForagingSaveFileConverter was getting too big and unwieldy. Modified Paths: -------------- foraging/trunk/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java Added Paths: ----------- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateCollectedTokenNeighborProcessor.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTimeIntervalProcessor.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTokenSpatialDistributionProcessor.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AllDataProcessor.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementStatistics.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementTokenCount.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientSpatialDistribution.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/CollectedTokenSpatialDistributionProcessor.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/MovementStatisticsProcessor.java foraging/trunk/src/main/java/edu/asu/commons/foraging/data/SummaryProcessor.java Removed Paths: ------------- foraging/trunk/src/main/java/edu/asu/commons/foraging/util/ForagingSaveFileConverter.java Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateCollectedTokenNeighborProcessor.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateCollectedTokenNeighborProcessor.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateCollectedTokenNeighborProcessor.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,147 @@ +package edu.asu.commons.foraging.data; + +import java.awt.Point; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeSet; + +import edu.asu.commons.event.PersistableEvent; +import edu.asu.commons.experiment.SaveFileProcessor; +import edu.asu.commons.experiment.SavedRoundData; +import edu.asu.commons.foraging.client.Circle; +import edu.asu.commons.foraging.conf.RoundConfiguration; +import edu.asu.commons.foraging.event.MovementEvent; +import edu.asu.commons.foraging.event.ResourceAddedEvent; +import edu.asu.commons.foraging.event.ResourcesAddedEvent; +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.net.Identifier; +import edu.asu.commons.util.Utils; + +/** + * $Id$ + * + * Generates aggregate distributions of the number of neighboring tokens for a collected token in two situations: + * 1. without regard to visibility + * 2. only when other subjects are visible. + * + * @author <a href='mailto:all...@as...'>Allen Lee</a> + * @version $Rev$ + */ +public class AggregateCollectedTokenNeighborProcessor extends SaveFileProcessor.Base { + + private final static Object[] NEIGHBORING_TOKEN_HEADER = { + "0", "1", "2", "3", "4", "5", "6", "7", "8" + }; + + public AggregateCollectedTokenNeighborProcessor() { + setSecondsPerInterval(ForagingSaveFileConverter.DEFAULT_AGGREGATE_TIME_INTERVAL); + } + + private boolean hasOtherSubjectsInView(Identifier id, Point location, GroupDataModel group) { + RoundConfiguration roundConfiguration = group.getRoundConfiguration(); + if (roundConfiguration.isFieldOfVisionEnabled()) { + Circle circle = new Circle(location, roundConfiguration.getViewSubjectsRadius()); + for (Map.Entry<Identifier, Point> entry : group.getClientPositions().entrySet()) { + if (entry.getKey().equals(id)) { + // skip if this is the same client + continue; + } + if (circle.contains(entry.getValue())) { + return true; + } + } + return false; + } + // field of vision isn't enabled, everyone is in everyone else's field of view. + return true; + } + + public void process(SavedRoundData savedRoundData, PrintWriter writer) { + // populate the ordered identifiers, try directly from the participant tokens map that + // is persisted in later versions of the experiment. + ServerDataModel serverDataModel = (ServerDataModel) savedRoundData.getDataModel(); + TreeSet<Identifier> orderedIdentifiers = new TreeSet<Identifier>(serverDataModel.getClientDataMap().keySet()); + // write out header for collected tokens statistics. + // second token header is the distribution for token harvests when other subjects are in the field of view. + writer.println( + Utils.join(',', "Time", "Client ID", + Utils.join(',', NEIGHBORING_TOKEN_HEADER), + Utils.join(',', NEIGHBORING_TOKEN_HEADER))); + Map<Identifier, Integer[]> collectedTokenNeighborsWithOtherSubjectsInView = new LinkedHashMap<Identifier, Integer[]>(); + Map<Identifier, Integer[]> collectedTokenNeighbors = new LinkedHashMap<Identifier, Integer[]>(); + for (Identifier id: orderedIdentifiers) { + Integer[] neighbors = new Integer[9]; + Integer[] neighborsWithOtherSubjectsInView = new Integer[9]; + Arrays.fill(neighbors, 0); + Arrays.fill(neighborsWithOtherSubjectsInView, 0); + collectedTokenNeighbors.put(id, neighbors); + collectedTokenNeighborsWithOtherSubjectsInView.put(id, neighborsWithOtherSubjectsInView); + } + // initialize client positions + for (ClientData clientData: serverDataModel.getClientDataMap().values()) { + clientData.initializePosition(); + } + for (PersistableEvent event: savedRoundData.getActions()) { + long elapsedTimeInSeconds = savedRoundData.getElapsedTimeInSeconds(event); + if (isIntervalElapsed(elapsedTimeInSeconds)) { + writeAggregateStatistics(writer, collectedTokenNeighbors, collectedTokenNeighborsWithOtherSubjectsInView); + } + if (event instanceof ResourceAddedEvent) { + ResourceAddedEvent rae = (ResourceAddedEvent) event; + assert serverDataModel.getGroup(rae.getId()).equals(rae.getGroup()); + rae.getGroup().addResource(rae.getResource()); + } + else if (event instanceof ResourcesAddedEvent) { + ResourcesAddedEvent rae = (ResourcesAddedEvent) event; + assert serverDataModel.getGroup(rae.getId()).equals(rae.getGroup()); + rae.getGroup().addResources(rae.getResources()); + } + else if (event instanceof TokenCollectedEvent) { + TokenCollectedEvent tce = (TokenCollectedEvent) event; + Identifier id = tce.getId(); + Point location = tce.getLocation(); + GroupDataModel group = serverDataModel.getGroup(id); + int numberOfNeighboringTokens = group.getNumberOfNeighboringTokens(location); + collectedTokenNeighbors.get(id)[numberOfNeighboringTokens]++; + if (hasOtherSubjectsInView(id, location, group)) { + collectedTokenNeighborsWithOtherSubjectsInView.get(id)[numberOfNeighboringTokens]++; + } + } + else if (event instanceof MovementEvent) { + MovementEvent movementEvent = (MovementEvent) event; + serverDataModel.moveClient(movementEvent.getId(), movementEvent.getDirection()); + } + } + // write out last interval + writeAggregateStatistics(writer, collectedTokenNeighbors, collectedTokenNeighborsWithOtherSubjectsInView); + } + + private void writeAggregateStatistics(PrintWriter writer, + Map<Identifier, Integer[]> collectedTokenNeighbors, + Map<Identifier, Integer[]> collectedTokenNeighborsWithOtherSubjectsInView) { + // write all collected data + for (Map.Entry<Identifier, Integer[]> entry : collectedTokenNeighbors.entrySet()) { + Identifier id = entry.getKey(); + Integer[] neighboringTokens = entry.getValue(); + Integer[] neighboringTokensWithOtherSubjectsInView = collectedTokenNeighborsWithOtherSubjectsInView.get(id); + writer.println(Utils.join(',', getIntervalEnd(), id, + Utils.join(',', Arrays.asList(neighboringTokens)), + Utils.join(',', Arrays.asList(neighboringTokensWithOtherSubjectsInView)))); + // clear old neighboring tokens + Arrays.fill(neighboringTokens, 0); + Arrays.fill(neighboringTokensWithOtherSubjectsInView, 0); + } + } + + @Override + public String getOutputFileExtension() { + return "-collected-token-neighbors.txt"; + } + + +} \ No newline at end of file Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateCollectedTokenNeighborProcessor.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTimeIntervalProcessor.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTimeIntervalProcessor.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTimeIntervalProcessor.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,226 @@ +package edu.asu.commons.foraging.data; + +import java.awt.Point; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +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.ClientPoseUpdate; +import edu.asu.commons.foraging.event.HarvestFruitRequest; +import edu.asu.commons.foraging.event.HarvestResourceRequest; +import edu.asu.commons.foraging.event.MovementEvent; +import edu.asu.commons.foraging.event.ResourceAddedEvent; +import edu.asu.commons.foraging.event.ResourcesAddedEvent; +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.ResourceDispenser; +import edu.asu.commons.foraging.model.ServerDataModel; +import edu.asu.commons.foraging.model.StochasticGenerator; +import edu.asu.commons.net.Identifier; +import edu.asu.commons.util.Utils; + +/** + * $Id$ + * + * Generates aggregate statistics + * + * @author <a href='mailto:all...@as...'>Allen Lee</a> + * @version $Rev$ + */ +public class AggregateTimeIntervalProcessor extends SaveFileProcessor.Base { + public AggregateTimeIntervalProcessor() { + setSecondsPerInterval(ForagingSaveFileConverter.DEFAULT_AGGREGATE_TIME_INTERVAL); + } + public void process(SavedRoundData savedRoundData, PrintWriter writer) { + // populate the ordered identifiers, try directly from the participant tokens map that + // is persisted in later versions of the experiment. + ServerDataModel serverDataModel = (ServerDataModel) savedRoundData.getDataModel(); + Map<Identifier, ClientMovementTokenCount> clientStatistics = ClientMovementTokenCount.createMap(serverDataModel); + for (ClientData clientData: serverDataModel.getClientDataMap().values()) { + clientData.initializePosition(); + } + RoundConfiguration roundConfiguration = (RoundConfiguration) savedRoundData.getRoundParameters(); + TreeSet<Identifier> orderedIdentifiers = new TreeSet<Identifier>(serverDataModel.getClientDataMap().keySet()); + List<GroupDataModel> groups = new ArrayList<GroupDataModel>(serverDataModel.getGroups()); + + List<String> movementHeader = new ArrayList<String>(); + List<String> collectedTokensHeader = new ArrayList<String>(); + for (Identifier id: orderedIdentifiers) { + movementHeader.add(id + " moves"); + collectedTokensHeader.add(id + " tokens collected"); + } + + // headers for average probability of a token for each group + // List<String> tokenProbabilityGroupNumberHeader = new ArrayList<String>(); + // headers for tokens left in each group + // List<String> tokensLeftGroupNumberHeader = new ArrayList<String>(); + List<String> distanceHeader = new ArrayList<String>(); + + for (int groupIndex = 0; groupIndex < groups.size(); groupIndex++) { + String groupNumber = "Group-" + groupIndex; + // tokenProbabilityGroupNumberHeader.add(groupNumber + " avg token P"); + // tokensLeftGroupNumberHeader.add(groupNumber + " tokens left"); + + List<Identifier> ids = new ArrayList<Identifier>(groups.get(groupIndex).getOrderedClientIdentifiers()); + for (int i = 0; i < ids.size(); i++) { + Identifier id = ids.get(i); + for (int j = i+1; j < ids.size(); j++) { + Identifier secondId = ids.get(j); + distanceHeader.add(String.format("%s (%s -> %s)", groupNumber, id, secondId)); + } + } + } + + // write out the header + String header = Utils.join(',', "Period", + // moves taken + Utils.join(',', movementHeader), + // tokens + Utils.join(',', collectedTokensHeader), + // group token probabilities + // Utils.join(',', tokenProbabilityGroupNumberHeader), + // group total tokens left + // Utils.join(',', tokensLeftGroupNumberHeader), + // distance between participants + Utils.join(',', distanceHeader) + ); + writer.println(header); + + for (PersistableEvent event: savedRoundData.getActions()) { + long secondsElapsed = savedRoundData.getElapsedTimeInSeconds(event); + // see if the current persistable event is past the threshold, + // meaning we should take a snapshot of our currently + // accumulated stats + if (isIntervalElapsed(secondsElapsed)) { + // generate group expected token counts + writeAggregateStatistics(writer, serverDataModel, + clientStatistics, orderedIdentifiers, groups); + } + // next, process the current persistable event + ClientMovementTokenCount stats = clientStatistics.get(event.getId()); + if (event instanceof MovementEvent) { + MovementEvent movementEvent = (MovementEvent) event; + serverDataModel.moveClient(movementEvent.getId(), movementEvent.getDirection()); + stats.moves++; + } + else if (event instanceof ClientPoseUpdate) { + ClientPoseUpdate clientPoseUpdate = (ClientPoseUpdate) event; + serverDataModel.getClientDataMap().get(event.getId()).setPosition(clientPoseUpdate.getPosition()); + stats.moves++; + } + else if (event instanceof TokenCollectedEvent) { + stats.tokens++; + TokenCollectedEvent tokenCollectedEvent = (TokenCollectedEvent) event; + GroupDataModel group = serverDataModel.getGroup(tokenCollectedEvent.getId()); + assert serverDataModel.getGroups().contains(group); + group.removeResource(tokenCollectedEvent.getLocation()); + } + else if (event instanceof HarvestFruitRequest) { +// HarvestFruitRequest request = (HarvestFruitRequest) event; + stats.tokens += roundConfiguration.getTokensPerFruits(); + } + else if (event instanceof HarvestResourceRequest) { + HarvestResourceRequest request = (HarvestResourceRequest) event; + stats.tokens += roundConfiguration.ageToTokens(request.getResource().getAge()); + } + else if (event instanceof ResourceAddedEvent) { + ResourceAddedEvent resourceAddedEvent = (ResourceAddedEvent) event; + assert serverDataModel.getGroups().contains(resourceAddedEvent.getGroup()); + resourceAddedEvent.getGroup().addResource(resourceAddedEvent.getPosition()); + } + else if (event instanceof ResourcesAddedEvent) { + ResourcesAddedEvent resourcesAddedEvent = (ResourcesAddedEvent) event; + assert serverDataModel.getGroups().contains(resourcesAddedEvent.getGroup()); + resourcesAddedEvent.getGroup().addResources(resourcesAddedEvent.getResources()); + } + } + writeAggregateStatistics(writer, serverDataModel, + clientStatistics, orderedIdentifiers, groups); + } + + private void writeAggregateStatistics(PrintWriter writer, + ServerDataModel serverDataModel, + Map<Identifier, ClientMovementTokenCount> clientStatistics, + TreeSet<Identifier> orderedIdentifiers, + List<GroupDataModel> groups) { + List<Double> expectedTokenProbabilities = getExpectedTokenProbabilities(serverDataModel); + // report summary stats and reset + List<Integer> movesTaken = new ArrayList<Integer>(); + List<Integer> harvestedTokens = new ArrayList<Integer>(); + List<Integer> tokensLeft = getTokensLeft(groups); + List<Double> distances = getClientDistances(groups); + for (Identifier id : orderedIdentifiers) { + ClientMovementTokenCount stats = clientStatistics.get(id); + movesTaken.add(stats.moves); + harvestedTokens.add(stats.tokens); + stats.reset(); + } + String dataline = + Utils.join(',', getIntervalEnd(), + Utils.join(',', movesTaken), + Utils.join(',', harvestedTokens), + Utils.join(',', expectedTokenProbabilities), + Utils.join(',', tokensLeft), + Utils.join(',', distances) + ); + writer.println(dataline); + } + + private List<Double> getClientDistances(List<GroupDataModel> groups) { + List<Double> distances = new ArrayList<Double>(); + for (GroupDataModel group: groups) { + List<Identifier> ids = new ArrayList<Identifier>(group.getOrderedClientIdentifiers()); + for (int i = 0; i < ids.size(); i++) { + Identifier id = ids.get(i); + for (int j = i+1; j < ids.size(); j++) { + Identifier secondId = ids.get(j); + distances.add(group.getClientPosition(id).distance(group.getClientPosition(secondId))); + } + } + } + return distances; + } + + private List<Double> getExpectedTokenProbabilities(ServerDataModel state) { + List<Double> expectedTokens = new ArrayList<Double>(); + Set<GroupDataModel> groups = state.getGroups(); + ResourceDispenser dispenser = new ResourceDispenser(state); + StochasticGenerator generator = dispenser.getDensityDependentGenerator(); + for (GroupDataModel group: groups) { + double tokenProbabilitySum = 0; + for (int x = 0; x < state.getBoardWidth(); x++) { + for (int y = 0; y < state.getBoardHeight(); y++) { + if (! group.getResourcePositions().contains(new Point(x, y))) { + tokenProbabilitySum += generator.getProbabilityForCell(group, x, y); + } + } + } + expectedTokens.add(tokenProbabilitySum); + } + return expectedTokens; + } + + private List<Integer> getTokensLeft(Collection<GroupDataModel> groups) { + List<Integer> tokensLeft = new ArrayList<Integer>(); + for (GroupDataModel group: groups) { + tokensLeft.add(group.getResourceDistributionSize()); + } + return tokensLeft; + } + + @Override + public String getOutputFileExtension() { + return "-aggregated-time-interval-data.txt"; + } + + +} \ No newline at end of file Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTimeIntervalProcessor.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTokenSpatialDistributionProcessor.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTokenSpatialDistributionProcessor.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTokenSpatialDistributionProcessor.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,91 @@ +package edu.asu.commons.foraging.data; + +import java.awt.Dimension; +import java.awt.Point; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; + +import edu.asu.commons.event.PersistableEvent; +import edu.asu.commons.experiment.SaveFileProcessor; +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.GroupDataModel; +import edu.asu.commons.foraging.model.ServerDataModel; +import edu.asu.commons.net.Identifier; + +/** + * $Id$ + * + * + * @author <a href='mailto:all...@as...'>Allen Lee</a> + * @version $Rev$ + */ +class AggregateTokenSpatialDistributionProcessor extends SaveFileProcessor.Base { + public AggregateTokenSpatialDistributionProcessor() { + setSecondsPerInterval(ForagingSaveFileConverter.DEFAULT_AGGREGATE_TIME_INTERVAL); + } + @Override + public void process(SavedRoundData savedRoundData, PrintWriter writer) { + ServerDataModel serverDataModel = (ServerDataModel) savedRoundData.getDataModel(); + SortedSet<PersistableEvent> actions = savedRoundData.getActions(); + Map<Identifier, ClientSpatialDistribution> clientSpatialDistributionMap = new HashMap<Identifier, ClientSpatialDistribution>(); + Dimension boardSize = new Dimension(serverDataModel.getBoardWidth(), serverDataModel.getBoardHeight()); + for (ClientData clientData : serverDataModel.getClientDataMap().values()) { + clientSpatialDistributionMap.put(clientData.getId(), new ClientSpatialDistribution(boardSize)); + } + for (PersistableEvent event : actions) { + long elapsedTime = savedRoundData.getElapsedTimeInSeconds(event); + if (isIntervalElapsed(elapsedTime)) { + writeData(writer, serverDataModel, clientSpatialDistributionMap); + } + if (event instanceof TokenCollectedEvent) { + TokenCollectedEvent tokenCollectedEvent = (TokenCollectedEvent) event; + Point point = tokenCollectedEvent.getLocation(); + Identifier id = tokenCollectedEvent.getId(); + ClientSpatialDistribution spatialDistribution = clientSpatialDistributionMap.get(id); + spatialDistribution.columnCounts[point.x]++; + spatialDistribution.rowCounts[point.y]++; + spatialDistribution.tokens++; + } + } + // write last interval out + writeData(writer, serverDataModel, clientSpatialDistributionMap); + } + + private void writeData( + PrintWriter writer, + ServerDataModel serverDataModel, + Map<Identifier, ClientSpatialDistribution> clientSpatialDistributionMap) + { + ArrayList<GroupDataModel> groups = new ArrayList<GroupDataModel>(serverDataModel.getGroups()); + for (GroupDataModel group: groups) { +// String groupLabel = "Group # " + groups.indexOf(group); + String groupLabel = group.toString(); + writer.println("Time, Identifier, Group, # tokens, row stdev, column stdev"); + double groupWeightedSpatialMetric = 0.0d; + int totalTokens = 0; + for (Identifier id: group.getClientIdentifiers()) { + ClientSpatialDistribution spatialDistribution = clientSpatialDistributionMap.get(id); + spatialDistribution.calculateStandardDeviation(); + groupWeightedSpatialMetric += spatialDistribution.weightedSpatialMetric; + writer.println(String.format("%d, %s, %s, %s, %s, %s", getIntervalEnd(), id, groupLabel, spatialDistribution.tokens, spatialDistribution.rowStandardDeviation, spatialDistribution.columnStandardDeviation)); + totalTokens += spatialDistribution.tokens; + } + groupWeightedSpatialMetric /= totalTokens; + writer.println(groupLabel + " weighted spatial metric: " + groupWeightedSpatialMetric); + } + // clear data after processing all groups. + for (ClientSpatialDistribution spatialDistribution : clientSpatialDistributionMap.values()) { + spatialDistribution.zeroRowColumnCounts(); + } + } + + @Override + public String getOutputFileExtension() { + return "-aggregated-spatial-distribution.txt"; + } + } \ No newline at end of file Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AggregateTokenSpatialDistributionProcessor.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AllDataProcessor.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AllDataProcessor.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AllDataProcessor.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,198 @@ +package edu.asu.commons.foraging.data; + +import java.awt.Point; +import java.io.PrintWriter; +import java.util.Map; +import java.util.SortedSet; + +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.conf.RoundConfiguration; +import edu.asu.commons.foraging.event.EnforcementRankingRequest; +import edu.asu.commons.foraging.event.HarvestFruitRequest; +import edu.asu.commons.foraging.event.HarvestResourceRequest; +import edu.asu.commons.foraging.event.MovementEvent; +import edu.asu.commons.foraging.event.QuizResponseEvent; +import edu.asu.commons.foraging.event.RealTimeSanctionRequest; +import edu.asu.commons.foraging.event.ResourcesAddedEvent; +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.Resource; +import edu.asu.commons.foraging.model.ServerDataModel; +import edu.asu.commons.net.Identifier; +import edu.asu.commons.util.Utils; + +/** + * $Id$ + * + * Serializes all data in the save file into a CSV string format, ordered by time. + * + * + * @author <a href='mailto:all...@as...'>Allen Lee</a> + * @version $Rev$ + */ +class AllDataProcessor extends SaveFileProcessor.Base { + + @Override + public String getOutputFileExtension() { + return "-all-data.txt"; + } + + @Override + public void process(SavedRoundData savedRoundData, PrintWriter writer) { + RoundConfiguration roundConfiguration = (RoundConfiguration) savedRoundData.getRoundParameters(); + if (roundConfiguration.is2dExperiment()) { + processData2d(savedRoundData, writer); + } + else { + processData3d(savedRoundData, writer); + } + } + + private void processData2d(SavedRoundData savedRoundData, PrintWriter writer) { + // RoundConfiguration roundConfiguration = (RoundConfiguration) savedRoundData.getRoundParameters(); + SortedSet<PersistableEvent> actions = savedRoundData.getActions(); + ServerDataModel model = (ServerDataModel) savedRoundData.getDataModel(); + Map<Identifier, ClientMovementTokenCount> clientMovementTokenCounts = ClientMovementTokenCount.createMap(model); +// List<GroupDataModel> groups = new ArrayList<GroupDataModel>(model.getGroups()); + Map<Identifier, ClientData> clientDataMap = model.getClientDataMap(); + for (PersistableEvent event: actions) { + if (event instanceof MovementEvent) { + MovementEvent movementEvent = (MovementEvent) event; + ClientData clientData = clientDataMap.get(event.getId()); + ClientMovementTokenCount client = clientMovementTokenCounts.get(event.getId()); + client.moves++; + GroupDataModel group = clientData.getGroupDataModel(); + String line = String.format("%s, %s, %d, %d, %s, %s", + savedRoundData.toSecondString(event), + clientData.getId(), + group.getGroupId(), + client.moves, + movementEvent.getDirection(), + "movement event" + ); + writer.println(line); + } + else if (event instanceof TokenCollectedEvent) { + TokenCollectedEvent tokenCollectedEvent = (TokenCollectedEvent) event; + ClientData clientData = clientDataMap.get(event.getId()); + ClientMovementTokenCount client = clientMovementTokenCounts.get(event.getId()); + Point location = tokenCollectedEvent.getLocation(); + client.tokens++; + GroupDataModel group = clientData.getGroupDataModel(); + String line = String.format("%s, %s, %d, %d, %d, %d, %s", + savedRoundData.toSecondString(event), + clientData.getId(), + location.x, + location.y, + group.getGroupId(), + client.tokens, + "token collected event"); + writer.println(line); + } + else if (event instanceof ResourcesAddedEvent) { + ResourcesAddedEvent resourcesAddedEvent = (ResourcesAddedEvent) event; + String line = String.format("%s, %s, %s, %s", savedRoundData.toSecondString(event), resourcesAddedEvent.getClass(), resourcesAddedEvent.getGroup().toString(), resourcesAddedEvent.getResourcePositions()); + writer.println(line); + } + else if (event instanceof ChatRequest) { + ChatRequest request = (ChatRequest) event; + Identifier sourceId = request.getSource(); + Identifier targetId = request.getTarget(); + String message = request.toString(); + String line = String.format("%s, %s, %s, %s", savedRoundData.toSecondString(event), sourceId, targetId, message); + System.err.println(line); + writer.println(line); + } + else if (event instanceof RealTimeSanctionRequest) { + RealTimeSanctionRequest request = (RealTimeSanctionRequest) event; + Identifier source = request.getSource(); + Identifier target = request.getTarget(); + String line = String.format("%s, %s, %s, %s", savedRoundData.toSecondString(event), source, target, request.toString()); + writer.println(line); + } + else if (event instanceof QuizResponseEvent) { + QuizResponseEvent response = (QuizResponseEvent) event; + String line = String.format("%s, %s", savedRoundData.toSecondString(event), response.toString()); + writer.println(line); + } + else if (event instanceof EnforcementRankingRequest) { + System.err.println("enforcement ranking request: " + event); + EnforcementRankingRequest request = (EnforcementRankingRequest) event; + String line = String.format("%s, %s", savedRoundData.toSecondString(event), request.toString()); + writer.println(line); + } + else { + writer.println(String.format("%s, %s", savedRoundData.toSecondString(event), event.toString())); + } + } + } + + private void processData3d(SavedRoundData savedRoundData, PrintWriter writer) { + RoundConfiguration roundConfiguration = (RoundConfiguration) savedRoundData.getRoundParameters(); + ServerDataModel dataModel = (ServerDataModel) savedRoundData.getDataModel(); + Map<Identifier, ClientMovementTokenCount> clientStatsMap = ClientMovementTokenCount.createMap(dataModel); + SortedSet<PersistableEvent> actions = savedRoundData.getActions(); + for (PersistableEvent event: actions) { + if (event instanceof ChatRequest) { + ChatRequest request = (ChatRequest) event; + Identifier sourceId = request.getSource(); + Identifier targetId = request.getTarget(); + String message = request.toString(); + String line = String.format("%s, %s, %s, %s", + savedRoundData.toSecondString(event), + sourceId, + targetId, + message); + writer.println(line); + } + else if (event instanceof ResourcesAddedEvent) { + ResourcesAddedEvent resourcesAddedEvent = (ResourcesAddedEvent) event; + String line = String.format("%s, %s, %s", + savedRoundData.toSecondString(event), + resourcesAddedEvent.getGroup(), + Utils.join(',', resourcesAddedEvent.getResourcePositions())); + System.err.println("resources added event: " + line); + writer.println(line); + } + else if (event instanceof HarvestFruitRequest) { + HarvestFruitRequest request = (HarvestFruitRequest) event; + ClientMovementTokenCount clientStats = clientStatsMap.get(event.getId()); + clientStats.tokens += roundConfiguration.getTokensPerFruits(); + Resource resource = request.getResource(); + String line = String.format("%s, %s, %d, %d, %d, %d, %d, %d, %s", + savedRoundData.toSecondString(event), + event.getId(), + resource.getPosition().x, + resource.getPosition().y, + 1, + resource.getAge(), + roundConfiguration.getTokensPerFruits(), + clientStats.tokens, + "harvest fruit"); + writer.println(line); + } + else if (event instanceof HarvestResourceRequest) { + HarvestResourceRequest request = (HarvestResourceRequest) event; + Resource resource = request.getResource(); + ClientMovementTokenCount clientStats = clientStatsMap.get(event.getId()); + clientStats.tokens += roundConfiguration.ageToTokens(resource.getAge()); + String line = String.format("%s, %s, %d, %d, %d, %d, %d, %d, %s", + savedRoundData.toSecondString(event), + event.getId(), + resource.getPosition().x, + resource.getPosition().y, + 0, + resource.getAge(), + roundConfiguration.ageToTokens(resource.getAge()), + clientStats.tokens, + "harvest resource"); + System.err.println("harvest resource request: " + line); + writer.println(line); + } + } + } +} \ No newline at end of file Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/AllDataProcessor.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementStatistics.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementStatistics.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementStatistics.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,72 @@ +package edu.asu.commons.foraging.data; + +import edu.asu.commons.foraging.conf.RoundConfiguration; +import edu.asu.commons.foraging.model.Direction; +import edu.asu.commons.net.Identifier; + +/** + * $Id$ + * + * Helper class to keep track of client movements. + * + * @author <a href='mailto:all...@as...'>Allen Lee</a> + * @version $Rev$ + */ +class ClientMovementStatistics { + private final Identifier id; + private Direction lastDirection; + // distribution of moves, each entry in the array represents the number of times they've moved. + private int[] movementDistribution; + private int currentMoveCount = 0; + private int allMoves; + + public ClientMovementStatistics(Identifier id, RoundConfiguration configuration) { + this.id = id; + int maximumNumberOfMoves = Math.max(configuration.getBoardSize().height, configuration.getBoardSize().width); + movementDistribution = new int[maximumNumberOfMoves]; + } + + void incrementMovementDistribution() { + int movementDistributionIndex = Math.min(currentMoveCount, movementDistribution.length-1); + if (movementDistributionIndex > 0) { + movementDistribution[movementDistributionIndex-1]++; + } + currentMoveCount = 1; + } + + public synchronized void move(Direction direction) { + if (direction != null) { + allMoves++; + } + if (lastDirection == null) { + lastDirection = direction; + currentMoveCount = 1; + } + else if (lastDirection.equals(direction)) { + currentMoveCount++; + } + else { + lastDirection = direction; + incrementMovementDistribution(); + } + } + + public Integer[] getMovementDistribution() { + Integer[] rv = new Integer[movementDistribution.length]; + for (int i = 0; i < movementDistribution.length; i++) { + rv[i] = Integer.valueOf(movementDistribution[i]); + } + return rv; + } + + public void validate() { + int sum = 0; + for (int i = 0; i < movementDistribution.length; i++) { + // i+1 to offset zero-based array index + sum += ((i+1) * movementDistribution[i]); + } + if (allMoves != sum) { + throw new RuntimeException("Identifier id: " + id + " -- allMoves: " + allMoves + " not equal to sum of all moves: " + sum); + } + } +} \ No newline at end of file Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementStatistics.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementTokenCount.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementTokenCount.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementTokenCount.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,33 @@ +package edu.asu.commons.foraging.data; + +import java.util.HashMap; +import java.util.Map; + +import edu.asu.commons.foraging.model.ServerDataModel; +import edu.asu.commons.net.Identifier; + +/** + * $Id$ + * + * Helper class for maintaining basic movement / token information. + * + * + * @author <a href='mailto:all...@as...'>Allen Lee</a> + * @version $Rev$ + */ +class ClientMovementTokenCount { + int moves = 0; + int tokens = 0; + public void reset() { + moves = 0; + tokens = 0; + } + + public static Map<Identifier, ClientMovementTokenCount> createMap(ServerDataModel model) { + Map<Identifier, ClientMovementTokenCount> clientStats = new HashMap<Identifier, ClientMovementTokenCount>(); + for (Identifier id: model.getClientDataMap().keySet()) { + clientStats.put(id, new ClientMovementTokenCount()); + } + return clientStats; + } +} \ No newline at end of file Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientMovementTokenCount.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientSpatialDistribution.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientSpatialDistribution.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientSpatialDistribution.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,65 @@ +package edu.asu.commons.foraging.data; + +import java.awt.Dimension; +import java.util.Arrays; + +/** + * + * Utility class to keep track of spatial distribution statistics. + * + * + */ +class ClientSpatialDistribution { + int[] rowCounts; + private double standardizedRowDistribution; + int[] columnCounts; + private double standardizedColumnDistribution; + int tokens = 0; + double rowStandardDeviation; + double columnStandardDeviation; + double weightedSpatialMetric; + + ClientSpatialDistribution(Dimension boardSize) { + rowCounts = new int[boardSize.height]; + columnCounts = new int[boardSize.width]; + zeroRowColumnCounts(); + } + + public void zeroRowColumnCounts() { + Arrays.fill(rowCounts, 0); + Arrays.fill(columnCounts, 0); + } + + public String toString() { + return String.format("tokens: %d, row: %s, col: %s", tokens, standardizedRowDistribution, standardizedColumnDistribution); + } + + void calculateStandardDeviation() { + rowStandardDeviation = stdDev(rowCounts); + columnStandardDeviation = stdDev(columnCounts); + double averageTokens = (double) tokens / (double) rowCounts.length; + standardizedRowDistribution = (rowStandardDeviation / averageTokens); + standardizedColumnDistribution = (columnStandardDeviation / averageTokens); + weightedSpatialMetric = tokens * (rowStandardDeviation + columnStandardDeviation); + } + + private double stdDev(int[] counts) { + // calculate mean + int totalTokensInRow = sum(counts); + double size = (double) counts.length; + double mean = (double) totalTokensInRow / size; + double sumOfSquares = 0; + for (int count : counts) { + double difference = count - mean; + sumOfSquares += (difference * difference); + } + return Math.sqrt(sumOfSquares / size); + } + private int sum(int[] count) { + int total = 0; + for (int tokens: count) { + total += tokens; + } + return total; + } +} \ No newline at end of file Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ClientSpatialDistribution.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/CollectedTokenSpatialDistributionProcessor.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/CollectedTokenSpatialDistributionProcessor.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/CollectedTokenSpatialDistributionProcessor.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,81 @@ +package edu.asu.commons.foraging.data; + +import java.awt.Dimension; +import java.awt.Point; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; + +import edu.asu.commons.event.PersistableEvent; +import edu.asu.commons.experiment.SaveFileProcessor; +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.GroupDataModel; +import edu.asu.commons.foraging.model.ServerDataModel; +import edu.asu.commons.net.Identifier; + +/** + * $Id$ + * + * Generates spatial distribution statistics. + * + * + * @author <a href='mailto:all...@as...'>Allen Lee</a> + * @version $Rev$ + */ +class CollectedTokenSpatialDistributionProcessor extends SaveFileProcessor.Base { + @Override + public void process(SavedRoundData savedRoundData, PrintWriter writer) { + ServerDataModel serverDataModel = (ServerDataModel) savedRoundData.getDataModel(); + SortedSet<PersistableEvent> actions = savedRoundData.getActions(); + Map<Identifier, ClientSpatialDistribution> clientSpatialDistributionMap = new HashMap<Identifier, ClientSpatialDistribution>(); + Dimension boardSize = new Dimension(serverDataModel.getBoardWidth(), serverDataModel.getBoardHeight()); + for (ClientData clientData : serverDataModel.getClientDataMap().values()) { + clientSpatialDistributionMap.put(clientData.getId(), new ClientSpatialDistribution(boardSize)); + } + for (PersistableEvent event : actions) { + if (event instanceof TokenCollectedEvent) { + TokenCollectedEvent tokenCollectedEvent = (TokenCollectedEvent) event; + Point point = tokenCollectedEvent.getLocation(); + Identifier id = tokenCollectedEvent.getId(); + ClientSpatialDistribution spatialDistribution = clientSpatialDistributionMap.get(id); + spatialDistribution.columnCounts[point.x]++; + spatialDistribution.rowCounts[point.y]++; + spatialDistribution.tokens++; + } + } + // calculate for group + writeData(writer, serverDataModel, clientSpatialDistributionMap); + } + + private void writeData( + PrintWriter writer, + ServerDataModel serverDataModel, + Map<Identifier, ClientSpatialDistribution> clientSpatialDistributionMap) { + ArrayList<GroupDataModel> groups = new ArrayList<GroupDataModel>(serverDataModel.getGroups()); + for (GroupDataModel group: groups) { +// String groupLabel = "Group #" + groups.indexOf(group); + String groupLabel = group.toString(); + writer.println("Identifier, Group, # tokens, row stdev, column stdev"); + double groupWeightedSpatialMetric = 0.0d; + int totalTokens = 0; + for (Identifier id: group.getClientIdentifiers()) { + ClientSpatialDistribution spatialDistribution = clientSpatialDistributionMap.get(id); + spatialDistribution.calculateStandardDeviation(); + groupWeightedSpatialMetric += spatialDistribution.weightedSpatialMetric; + writer.println(String.format("%s, %s, %s, %s, %s", id, groupLabel, spatialDistribution.tokens, spatialDistribution.rowStandardDeviation, spatialDistribution.columnStandardDeviation)); + totalTokens += spatialDistribution.tokens; + } + groupWeightedSpatialMetric /= totalTokens; + writer.println(groupLabel + " weighted spatial metric: " + groupWeightedSpatialMetric); + } + } + + @Override + public String getOutputFileExtension() { + return "-spatial-distribution.txt"; + } + } \ No newline at end of file Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/CollectedTokenSpatialDistributionProcessor.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Copied: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java (from rev 525, foraging/trunk/src/main/java/edu/asu/commons/foraging/util/ForagingSaveFileConverter.java) =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,58 @@ +package edu.asu.commons.foraging.data; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import edu.asu.commons.experiment.Persister; +import edu.asu.commons.experiment.SaveFileProcessor; + +/** + * $Id$ + * <p> + * Save file processors used to convert binary data files from the foraging experiment. + * + * @author <a href='mailto:All...@as...'>Allen Lee</a> + * @version $Rev$ + */ +public class ForagingSaveFileConverter { + + static final int DEFAULT_AGGREGATE_TIME_INTERVAL = 5; + + public static boolean convert(String saveDataDirectory) { + File allSaveFilesDirectory = new File(saveDataDirectory); + if (allSaveFilesDirectory.exists() && allSaveFilesDirectory.isDirectory()) { + List<SaveFileProcessor> processors = new ArrayList<SaveFileProcessor>(); + processors.addAll(Arrays.asList( + new AllDataProcessor(), + new AggregateTimeIntervalProcessor(), + new SummaryProcessor(), + new AggregateTokenSpatialDistributionProcessor(), + new CollectedTokenSpatialDistributionProcessor(), + new MovementStatisticsProcessor(), + new AggregateCollectedTokenNeighborProcessor() + // new MovieCreatorProcessor() + )); + Persister.processSaveFiles(allSaveFilesDirectory, processors); + return true; + } + return false; + } + + public static void main(String[] args) { + if (args.length == 0) { + System.err.println("Usage: java " + ForagingSaveFileConverter.class + " <save-data-directory>"); + System.exit(0); + } + if (convert(args[0])) { + System.err.println("Successfully converted files in " + args[0]); + } + else { + System.err.println(args[0] + " doesn't appear to be a valid save file directory."); + } + } + + + +} Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/ForagingSaveFileConverter.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/MovementStatisticsProcessor.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/MovementStatisticsProcessor.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/MovementStatisticsProcessor.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,102 @@ +package edu.asu.commons.foraging.data; + +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +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.MovementEvent; +import edu.asu.commons.foraging.event.ResourcesAddedEvent; +import edu.asu.commons.foraging.event.TokenCollectedEvent; +import edu.asu.commons.foraging.model.GroupDataModel; +import edu.asu.commons.foraging.model.ServerDataModel; +import edu.asu.commons.net.Identifier; +import edu.asu.commons.util.Utils; + +/** + * $Id$ + * + * + * @author <a href='mailto:all...@as...'>Allen Lee</a> + * @version $Rev$ + */ +class MovementStatisticsProcessor extends SaveFileProcessor.Base { + private Map<Identifier, ClientMovementStatistics> clientStatisticsMap = new LinkedHashMap<Identifier, ClientMovementStatistics>(); + private Map<GroupDataModel, Integer> resourceCountMap = new HashMap<GroupDataModel, Integer>(); + + @Override + public void process(SavedRoundData savedRoundData, PrintWriter writer) { + ServerDataModel serverDataModel = (ServerDataModel) savedRoundData.getDataModel(); + for (GroupDataModel group: serverDataModel.getGroups()) { + for (Identifier id: group.getOrderedClientIdentifiers()) { + clientStatisticsMap.put(id, new ClientMovementStatistics(id, (RoundConfiguration) savedRoundData.getRoundParameters())); + } + resourceCountMap.put(group, 0); + } + + for (PersistableEvent event: savedRoundData.getActions()) { + if (event instanceof MovementEvent) { + MovementEvent movementEvent = (MovementEvent) event; + Identifier id = movementEvent.getId(); + GroupDataModel groupDataModel = serverDataModel.getGroup(id); + // only count movements when the resource count is > 0 + if (resourceCountMap.get(groupDataModel) > 0) { + clientStatisticsMap.get(id).move(movementEvent.getDirection()); + } + else { + // stop counting for this group. + } + } + else if (event instanceof ResourcesAddedEvent) { + ResourcesAddedEvent resourcesAddedEvent = (ResourcesAddedEvent) event; + GroupDataModel group = resourcesAddedEvent.getGroup(); + int resources = resourceCountMap.get(group); + resources += resourcesAddedEvent.getResources().size(); + resourceCountMap.put(group, resources); + } + else if (event instanceof TokenCollectedEvent) { + TokenCollectedEvent tokenCollectedEvent = (TokenCollectedEvent) event; + Identifier id = tokenCollectedEvent.getId(); + GroupDataModel groupDataModel = serverDataModel.getGroup(id); + int resources = resourceCountMap.get(groupDataModel); + resourceCountMap.put(groupDataModel, resources - 1); + } + } + // tally their very last movement counts + // (since ClientMovementStatistics only adds to the movement distribution when they change direction) + for (ClientMovementStatistics summary: clientStatisticsMap.values()) { + summary.incrementMovementDistribution(); + } + int maximumMoves = Math.max(serverDataModel.getBoardHeight(), serverDataModel.getBoardWidth()); + final Integer[] movementHeader = new Integer[maximumMoves]; + for (int iotaIndex = 0; iotaIndex < maximumMoves; iotaIndex++) { + movementHeader[iotaIndex] = iotaIndex + 1; + } + + // write out the header line. + writer.println(Utils.join(',', "Identifier", Utils.join(',', Arrays.asList(movementHeader)))); + + // and then write out each Identifier's movement distribution. + for (Map.Entry<Identifier, ClientMovementStatistics> entry : clientStatisticsMap.entrySet()) { + writer.println(Utils.join(',', entry.getKey(), Utils.join(',', + Arrays.asList(entry.getValue().getMovementDistribution())))); + } + } + + @Override + public String getOutputFileExtension() { + return "-movement-summary-statistics.txt"; + } + + @Override + public void dispose() { + clientStatisticsMap.clear(); + resourceCountMap.clear(); + } + +} \ No newline at end of file Property changes on: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/MovementStatisticsProcessor.java ___________________________________________________________________ Added: svn:keywords + Date Id Rev Added: foraging/trunk/src/main/java/edu/asu/commons/foraging/data/SummaryProcessor.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/data/SummaryProcessor.java (rev 0) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/data/SummaryProcessor.java 2010-08-06 01:25:27 UTC (rev 526) @@ -0,0 +1,87 @@ +package edu.asu.commons.foraging.data; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import edu.asu.commons.event.ChatRequest; +import edu.asu.commons.experiment.SaveFileProcessor; +import edu.asu.commons.experiment.SavedRoundData; +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; + +/** + * $Id$ + * + * + * @author <a href='mailto:all...@as...'>Allen Lee</a> + * @version $Rev$ + */ +class SummaryProcessor extends SaveFileProcessor.Base { + @Override + public void process(SavedRoundData savedRoundData, PrintWriter writer) { + ServerDataModel serverDataModel = (ServerDataModel) savedRoundData.getDataModel(); + List<GroupDataModel> groups = new ArrayList<GroupDataModel>(serverDataModel.getGroups()); + for (GroupDataModel group: groups) { + int totalConsumedGroupTokens = 0; + ArrayList<String> clientTokens = new ArrayList<String>(); + 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()); + } + }); + for (ClientData data : clientDataList) { + clientTokens.add(String.format("%s, %s, %s", data.getId(), data.getAssignedNumber(), data.getTotalTokens())); + totalConsumedGroupTokens += data.getTotalTokens(); + } + writer.println( + String.format("%s, %s, %s, %s", + group, + Utils.join(',', clientTokens), + group.... [truncated message content] |
From: <al...@us...> - 2010-08-06 01:00:23
|
Revision: 525 http://virtualcommons.svn.sourceforge.net/virtualcommons/?rev=525&view=rev Author: alllee Date: 2010-08-06 01:00:16 +0000 (Fri, 06 Aug 2010) Log Message: ----------- patching AggregateCollectedTokenNeighborProcessor to provide a second distribution of collected tokens' neighbors when other subjects are visible from that token collection location. Modified Paths: -------------- foraging/trunk/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java foraging/trunk/src/main/java/edu/asu/commons/foraging/util/ForagingSaveFileConverter.java Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java 2010-08-06 00:53:30 UTC (rev 524) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java 2010-08-06 01:00:16 UTC (rev 525) @@ -21,7 +21,6 @@ import edu.asu.commons.event.EndRoundRequest; import edu.asu.commons.event.EventTypeProcessor; import edu.asu.commons.event.FacilitatorRegistrationRequest; -import edu.asu.commons.event.RoundEndedMarkerEvent; import edu.asu.commons.event.RoundStartedMarkerEvent; import edu.asu.commons.event.SetConfigurationEvent; import edu.asu.commons.event.SocketIdentifierUpdateRequest; @@ -898,7 +897,8 @@ private void stopRound() { serverState = ServerState.WAITING; - persister.store(new RoundEndedMarkerEvent()); + // FIXME: not needed, persister.persist() automatically adds this. +// persister.store(new RoundEndedMarkerEvent()); sendEndRoundEvents(); if (getCurrentRoundConfiguration().isPostRoundSanctioningEnabled()) { // stop most of the round but don't persist/cleanup yet. @@ -911,7 +911,7 @@ } persistRound(); cleanupRound(); - // FIXME: Why is this here again..? are events getting to the client too soon? + // FIXME: make sure this is needed and document. Utils.sleep(2000); advanceToNextRound(); } Modified: foraging/trunk/src/main/java/edu/asu/commons/foraging/util/ForagingSaveFileConverter.java =================================================================== --- foraging/trunk/src/main/java/edu/asu/commons/foraging/util/ForagingSaveFileConverter.java 2010-08-06 00:53:30 UTC (rev 524) +++ foraging/trunk/src/main/java/edu/asu/commons/foraging/util/ForagingSaveFileConverter.java 2010-08-06 01:00:16 UTC (rev 525) @@ -22,6 +22,7 @@ import edu.asu.commons.experiment.Persister; import edu.asu.commons.experiment.SaveFileProcessor; import edu.asu.commons.experiment.SavedRoundData; +import edu.asu.commons.foraging.client.Circle; import edu.asu.commons.foraging.conf.RoundConfiguration; import edu.asu.commons.foraging.event.ClientPoseUpdate; import edu.asu.commons.foraging.event.EnforcementRankingRequest; @@ -630,40 +631,65 @@ public static class AggregateCollectedTokenNeighborProcessor extends SaveFileProcessor.Base { - - + private final static Object[] NEIGHBORING_TOKEN_HEADER = { + "0", "1", "2", "3", "4", "5", "6", "7", "8" + }; + public AggregateCollectedTokenNeighborProcessor() { setSecondsPerInterval(DEFAULT_AGGREGATE_TIME_INTERVAL); } + + private boolean hasOtherSubjectsInView(Identifier id, Point location, GroupDataModel group) { + RoundConfiguration roundConfiguration = group.getRoundConfiguration(); + if (roundConfiguration.isFieldOfVisionEnabled()) { + Circle circle = new Circle(location, roundConfiguration.getViewSubjectsRadius()); + for (Map.Entry<Identifier, Point> entry : group.getClientPositions().entrySet()) { + if (entry.getKey().equals(id)) { + // skip if this is the same client + continue; + } + if (circle.contains(entry.getValue())) { + return true; + } + } + return false; + } + // field of vision isn't enabled, everyone is in everyone else's field of view. + return true; + } public void process(SavedRoundData savedRoundData, PrintWriter writer) { // populate the ordered identifiers, try directly from the participant tokens map that // is persisted in later versions of the experiment. ServerDataModel serverDataModel = (ServerDataModel) savedRoundData.getDataModel(); TreeSet<Identifier> orderedIdentifiers = new TreeSet<Identifier>(serverDataModel.getClientDataMap().keySet()); - // write out neighboring tokens for collected tokens statistics first. - ArrayList<String> collectedTokenNeighborHeader = new ArrayList<String>(); - for (int i = 0; i < 9; i++) { - collectedTokenNeighborHeader.add(String.valueOf(i)); - } + // write out header for collected tokens statistics. + // second token header is the distribution for token harvests when other subjects are in the field of view. writer.println( Utils.join(',', "Time", "Client ID", - Utils.join(',', collectedTokenNeighborHeader))); + Utils.join(',', NEIGHBORING_TOKEN_HEADER), + Utils.join(',', NEIGHBORING_TOKEN_HEADER))); + Map<Identifier, Integer[]> collectedTokenNeighborsWithOtherSubjectsInView = new LinkedHashMap<Identifier, Integer[]>(); Map<Identifier, Integer[]> collectedTokenNeighbors = new LinkedHashMap<Identifier, Integer[]>(); for (Identifier id: orderedIdentifiers) { Integer[] neighbors = new Integer[9]; + Integer[] neighborsWithOtherSubjectsInView = new Integer[9]; Arrays.fill(neighbors, 0); + Arrays.fill(neighborsWithOtherSubjectsInView, 0); collectedTokenNeighbors.put(id, neighbors); + collectedTokenNeighborsWithOtherSubjectsInView.put(id, neighborsWithOtherSubjectsInView); } + // initialize client positions + for (ClientData clientData: serverDataModel.getClientDataMap().values()) { + clientData.initializePosition(); + } for (PersistableEvent event: savedRoundData.getActions()) { long elapsedTimeInSeconds = savedRoundData.getElapsedTimeInSeconds(event); - if (isIntervalElapsed(elapsedTimeInSeconds)) { - writeAggregateStatistics(writer, collectedTokenNeighbors); + writeAggregateStatistics(writer, collectedTokenNeighbors, collectedTokenNeighborsWithOtherSubjectsInView); } if (event instanceof ResourceAddedEvent) { ResourceAddedEvent rae = (ResourceAddedEvent) event; - // FIXME: check that rae.getGroup() is the same as the groups in the server data model assert serverDataModel.getGroup(rae.getId()).equals(rae.getGroup()); rae.getGroup().addResource(rae.getResource()); } @@ -675,26 +701,37 @@ else if (event instanceof TokenCollectedEvent) { TokenCollectedEvent tce = (TokenCollectedEvent) event; Identifier id = tce.getId(); - int numberOfNeighboringTokens = serverDataModel.getGroup(id).getNumberOfNeighboringTokens(tce.getLocation()); + Point location = tce.getLocation(); + GroupDataModel group = serverDataModel.getGroup(id); + int numberOfNeighboringTokens = group.getNumberOfNeighboringTokens(location); collectedTokenNeighbors.get(id)[numberOfNeighboringTokens]++; + if (hasOtherSubjectsInView(id, location, group)) { + collectedTokenNeighborsWithOtherSubjectsInView.get(id)[numberOfNeighboringTokens]++; + } } + else if (event instanceof MovementEvent) { + MovementEvent movementEvent = (MovementEvent) event; + serverDataModel.moveClient(movementEvent.getId(), movementEvent.getDirection()); + } } // write out last interval - writeAggregateStatistics(writer, collectedTokenNeighbors); + writeAggregateStatistics(writer, collectedTokenNeighbors, collectedTokenNeighborsWithOtherSubjectsInView); } private void writeAggregateStatistics(PrintWriter writer, - Map<Identifier, Integer[]> collectedTokenNeighbors) { + Map<Identifier, Integer[]> collectedTokenNeighbors, + Map<Identifier, Integer[]> collectedTokenNeighborsWithOtherSubjectsInView) { // write all collected data for (Map.Entry<Identifier, Integer[]> entry : collectedTokenNeighbors.entrySet()) { Identifier id = entry.getKey(); Integer[] neighboringTokens = entry.getValue(); + Integer[] neighboringTokensWithOtherSubjectsInView = collectedTokenNeighborsWithOtherSubjectsInView.get(id); writer.println(Utils.join(',', getIntervalEnd(), id, - Utils.join(',', Arrays.asList(neighboringTokens)))); - // replace old neighboring tokens with new array - Integer[] freshNeighbors = new Integer[9]; - Arrays.fill(freshNeighbors, 0); - entry.setValue(freshNeighbors); + Utils.join(',', Arrays.asList(neighboringTokens)), + Utils.join(',', Arrays.asList(neighboringTokensWithOtherSubjectsInView)))); + // clear old neighboring tokens + Arrays.fill(neighboringTokens, 0); + Arrays.fill(neighboringTokensWithOtherSubjectsInView, 0); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <al...@us...> - 2010-08-06 00:53:37
|
Revision: 524 http://virtualcommons.svn.sourceforge.net/virtualcommons/?rev=524&view=rev Author: alllee Date: 2010-08-06 00:53:30 +0000 (Fri, 06 Aug 2010) Log Message: ----------- switched AbstractEvent from nanoTime() back to currentTimeMillis() for a number of reasons, other minor hygiene Modified Paths: -------------- csidex/trunk/src/main/java/edu/asu/commons/client/BaseClient.java csidex/trunk/src/main/java/edu/asu/commons/conf/ExperimentRoundParameters.java csidex/trunk/src/main/java/edu/asu/commons/event/AbstractEvent.java csidex/trunk/src/main/java/edu/asu/commons/event/ChatRequest.java csidex/trunk/src/main/java/edu/asu/commons/event/RoundEndedMarkerEvent.java csidex/trunk/src/main/java/edu/asu/commons/experiment/Persister.java Removed Paths: ------------- csidex/trunk/src/main/java/edu/asu/commons/experiment/SavedExperimentData.java Modified: csidex/trunk/src/main/java/edu/asu/commons/client/BaseClient.java =================================================================== --- csidex/trunk/src/main/java/edu/asu/commons/client/BaseClient.java 2010-07-13 06:06:37 UTC (rev 523) +++ csidex/trunk/src/main/java/edu/asu/commons/client/BaseClient.java 2010-08-06 00:53:30 UTC (rev 524) @@ -61,7 +61,7 @@ public void connect() { initializeEventProcessors(); - id = dispatcher.connect(serverConfiguration.getServerAddress()); + this.id = dispatcher.connect(serverConfiguration.getServerAddress()); if (id == null) { throw new RuntimeException("Could not connect to server: <" + serverConfiguration.getServerAddress() Modified: csidex/trunk/src/main/java/edu/asu/commons/conf/ExperimentRoundParameters.java =================================================================== --- csidex/trunk/src/main/java/edu/asu/commons/conf/ExperimentRoundParameters.java 2010-07-13 06:06:37 UTC (rev 523) +++ csidex/trunk/src/main/java/edu/asu/commons/conf/ExperimentRoundParameters.java 2010-08-06 00:53:30 UTC (rev 524) @@ -141,6 +141,8 @@ public boolean isLastRound() { return parentConfiguration.isLastRound(); } + + // // public String getTemplate(String templateName) { // return assistant.transform(templateName, this); Modified: csidex/trunk/src/main/java/edu/asu/commons/event/AbstractEvent.java =================================================================== --- csidex/trunk/src/main/java/edu/asu/commons/event/AbstractEvent.java 2010-07-13 06:06:37 UTC (rev 523) +++ csidex/trunk/src/main/java/edu/asu/commons/event/AbstractEvent.java 2010-08-06 00:53:30 UTC (rev 524) @@ -33,7 +33,7 @@ this.id = Identifier.NULL; } this.id = id; - this.creationTime = System.nanoTime(); + this.creationTime = System.currentTimeMillis(); this.message = message; } Modified: csidex/trunk/src/main/java/edu/asu/commons/event/ChatRequest.java =================================================================== --- csidex/trunk/src/main/java/edu/asu/commons/event/ChatRequest.java 2010-07-13 06:06:37 UTC (rev 523) +++ csidex/trunk/src/main/java/edu/asu/commons/event/ChatRequest.java 2010-08-06 00:53:30 UTC (rev 524) @@ -16,16 +16,18 @@ private static final long serialVersionUID = 475300882222383637L; private final Identifier target; - private final String message; + public ChatRequest(Identifier source, String message) { + this(source, message, Identifier.ALL); + } + /** * A communication event with a target of Identifier.ALL is broadcast to all group participants. * @param source * @param message */ - public ChatRequest(Identifier id, String message, Identifier target) { - super(id); - this.message = message; + public ChatRequest(Identifier source, String message, Identifier target) { + super(source, message); this.target = target; } Modified: csidex/trunk/src/main/java/edu/asu/commons/event/RoundEndedMarkerEvent.java =================================================================== --- csidex/trunk/src/main/java/edu/asu/commons/event/RoundEndedMarkerEvent.java 2010-07-13 06:06:37 UTC (rev 523) +++ csidex/trunk/src/main/java/edu/asu/commons/event/RoundEndedMarkerEvent.java 2010-08-06 00:53:30 UTC (rev 524) @@ -7,7 +7,7 @@ * * Used to mark the end of a round in the save files. * - * + * @see RoundStartedMarkerEvent * @author <a href='mailto:All...@as...'>Allen Lee</a> * @version $Rev$ */ Modified: csidex/trunk/src/main/java/edu/asu/commons/experiment/Persister.java =================================================================== --- csidex/trunk/src/main/java/edu/asu/commons/experiment/Persister.java 2010-07-13 06:06:37 UTC (rev 523) +++ csidex/trunk/src/main/java/edu/asu/commons/experiment/Persister.java 2010-08-06 00:53:30 UTC (rev 524) @@ -224,11 +224,12 @@ logger.log(Level.SEVERE, "Error while processing [save directory: " + directory + "] - ignoring.", e); } } - @SuppressWarnings("unchecked") - public static ExperimentConfiguration restoreExperimentConfiguration(File saveDirectory) { + + @SuppressWarnings("rawtypes") + public static ExperimentConfiguration restoreExperimentConfiguration(File saveDirectory) { return restoreExperimentConfiguration(saveDirectory, DEFAULT_EXPERIMENT_CONFIGURATION_FILE); } - @SuppressWarnings("unchecked") + @SuppressWarnings("rawtypes") public static ExperimentConfiguration restoreExperimentConfiguration(File saveDirectory, String experimentConfigurationFilename) { if (experimentConfigurationFilename == null || "".equals(experimentConfigurationFilename)) { experimentConfigurationFilename = DEFAULT_EXPERIMENT_CONFIGURATION_FILE; @@ -270,7 +271,7 @@ save(serverDataModel); } - public final <E extends DataModel<R>> void save(E serverDataModel) { + private final <E extends DataModel<R>> void save(E serverDataModel) { try { saveRound(serverDataModel, persistenceDirectory); } Deleted: csidex/trunk/src/main/java/edu/asu/commons/experiment/SavedExperimentData.java =================================================================== --- csidex/trunk/src/main/java/edu/asu/commons/experiment/SavedExperimentData.java 2010-07-13 06:06:37 UTC (rev 523) +++ csidex/trunk/src/main/java/edu/asu/commons/experiment/SavedExperimentData.java 2010-08-06 00:53:30 UTC (rev 524) @@ -1,14 +0,0 @@ -package edu.asu.commons.experiment; - -import java.util.List; - -import edu.asu.commons.conf.ExperimentConfiguration; - -public class SavedExperimentData { - - private ExperimentConfiguration configuration; - - private List<SavedRoundData> roundData; - - -} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vir...@li...> - 2010-08-04 01:50:00
|
Subject: hg.virtualcommons 35 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/6c6423845a89 changeset: 35:6c6423845a89 user: alllee date: Tue Aug 03 18:45:52 2010 -0700 description: updated models diffstat: vcweb/core/auth.py | 20 ++++++++++++++-- vcweb/core/models.py | 34 +++++++++++++++++++++++++++- vcweb/core/templates/experimenter-index.html | 4 +- vcweb/core/templates/participant-index.html | 4 +- vcweb/core/views.py | 2 +- 5 files changed, 55 insertions(+), 9 deletions(-) diffs (141 lines): diff -r 1f67a3486ab5 -r 6c6423845a89 vcweb/core/auth.py --- a/vcweb/core/auth.py Mon Aug 02 14:56:28 2010 -0700 +++ b/vcweb/core/auth.py Tue Aug 03 18:45:52 2010 -0700 @@ -11,11 +11,25 @@ from django.contrib.auth.backends import ModelBackend -from django.contrib.auth.models import User + from django.core.validators import email_re -import logging +from vcweb.core.models import * -logger = logging.getLogger('CommonsAuthenticationBackend') + + +logger = logging.getLogger('vcweb.core.auth') + +def is_experimenter(user): + try: + return user.experimenter + except Experimenter.DoesNotExist: + return None + +def is_participant(user): + try: + return user.participant + except Participant.DoesNotExist: + return None class AuthenticationBackend(ModelBackend): def authenticate(self, username=None, password=None): diff -r 1f67a3486ab5 -r 6c6423845a89 vcweb/core/models.py --- a/vcweb/core/models.py Mon Aug 02 14:56:28 2010 -0700 +++ b/vcweb/core/models.py Tue Aug 03 18:45:52 2010 -0700 @@ -2,13 +2,14 @@ from django.core.validators import RegexValidator from django.db import models, transaction from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ from vcweb import settings import datetime import hashlib import logging import random import re -from django.utils.translation import ugettext_lazy as _ +from vcweb.core import auth SHA1_RE = re.compile('^[a-f0-9]{40}$') @@ -255,6 +256,16 @@ self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL) +## may use for urls.attribute_name trick shown in http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/ +#def attrproperty(getter_function): +# class _Object(object): +# def __init__(self, obj): +# self.obj = obj +# def __getattr__(self, attr): +# return getter_function(self.obj, attr) +# return property(_Object) + + # Create your models here. class GameMetadata(models.Model): title = models.CharField(max_length=255) @@ -343,9 +354,30 @@ end_date_time = models.DateTimeField(null=True, blank=True) @property + def url(self, request): + user = request.user + if user.is_authenticated(): + return "/{0}/{1}".format("participant" if auth.is_participant(user) else "experimenter", self.url_id) + else: + return self.namespace + + + @property + def participant_url(self): + return "/participant/{0}".format(self.url_id) + + @property + def management_url(self): + return "/experimenter/{0}".format(self.url_id) + + @property def namespace(self): return self.game_metadata.namespace + @property + def url_id(self): + return "{0}/{1}".format(self.game_metadata.namespace, self.id) + def __unicode__(self): return "{game} created by {experimenter} on {date_created}: {status}".format(game=self.game_metadata, experimenter=self.experimenter, date_created=self.date_created, status=self.status) diff -r 1f67a3486ab5 -r 6c6423845a89 vcweb/core/templates/experimenter-index.html --- a/vcweb/core/templates/experimenter-index.html Mon Aug 02 14:56:28 2010 -0700 +++ b/vcweb/core/templates/experimenter-index.html Tue Aug 03 18:45:52 2010 -0700 @@ -15,9 +15,9 @@ <legend>Your experiments</legend> <div class='sidebar'> <ul> -{% for game in games %} +{% for game_instance in games %} <li> -<a href='/experimenter/{{game.namespace}}/manage/{{game.id}}'> +<a href='{{game_instance.management_url}}'> {{ game }} </a> diff -r 1f67a3486ab5 -r 6c6423845a89 vcweb/core/templates/participant-index.html --- a/vcweb/core/templates/participant-index.html Mon Aug 02 14:56:28 2010 -0700 +++ b/vcweb/core/templates/participant-index.html Tue Aug 03 18:45:52 2010 -0700 @@ -14,9 +14,9 @@ <fieldset> <legend>Your experiments</legend> <ul> -{% for game in games %} +{% for game_instance in games %} <li> -<a href='/participate/{{game.namespace}}/{{game.id}}'>{{ game }}</a></li> +<a href='{{game_instance.participant_url}}'>{{ game_instance }}</a></li> {% endfor %} </ul> </fieldset> diff -r 1f67a3486ab5 -r 6c6423845a89 vcweb/core/views.py --- a/vcweb/core/views.py Mon Aug 02 14:56:28 2010 -0700 +++ b/vcweb/core/views.py Tue Aug 03 18:45:52 2010 -0700 @@ -64,7 +64,7 @@ games = [ group.game_instance for group in participant.group.all() ] return render_to_response('participant-index.html', RequestContext(request, locals())) except Participant.DoesNotExist: - # what to do? + # add error message return redirect('home') @login_required |
From: <vir...@li...> - 2010-08-02 21:55:51
|
Subject: hg.virtualcommons 34 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/1f67a3486ab5 changeset: 34:1f67a3486ab5 user: alllee date: Mon Aug 02 14:56:28 2010 -0700 description: updated model schema, using DateTimeFields as necessary. diffstat: vcweb/core/models.py | 17 +++++++++++------ 1 files changed, 11 insertions(+), 6 deletions(-) diffs (73 lines): diff -r 02c593012cf3 -r 1f67a3486ab5 vcweb/core/models.py --- a/vcweb/core/models.py Mon Aug 02 11:10:23 2010 -0700 +++ b/vcweb/core/models.py Mon Aug 02 14:56:28 2010 -0700 @@ -262,7 +262,7 @@ namespace = models.CharField(max_length=255, unique=True, validators=[RegexValidator(regex=r'^\w+$'), ]) description = models.TextField(null=True, blank=True) date_created = models.DateField(auto_now_add=True) - last_modified = models.DateField(auto_now=True) + last_modified = models.DateTimeField(auto_now=True) about_url = models.URLField(null=True, blank=True, verify_exists=True) logo_url = models.URLField(null=True, blank=True, verify_exists=True) default_game_configuration = models.ForeignKey('GameConfiguration', null=True, blank=True) @@ -311,7 +311,7 @@ name = models.CharField(max_length=255) maximum_number_of_participants = models.PositiveIntegerField() date_created = models.DateField(auto_now_add=True) - last_modified = models.DateField(auto_now=True) + last_modified = models.DateTimeField(auto_now=True) is_public = models.BooleanField(default=True) def __unicode__(self): @@ -335,12 +335,12 @@ game_configuration = models.ForeignKey(GameConfiguration) status = models.CharField(max_length=32, choices=GAME_STATUS_CHOICES) date_created = models.DateTimeField(auto_now_add=True) - start_time = models.TimeField(null=True, blank=True) + start_date_time = models.DateTimeField(null=True, blank=True) # how long this experiment should run duration = models.CharField(max_length=32) # duration of each tick. tick_duration = models.CharField(max_length=32) - end_time = models.DateTimeField(null=True, blank=True) + end_date_time = models.DateTimeField(null=True, blank=True) @property def namespace(self): @@ -362,6 +362,9 @@ game_configuration = models.ForeignKey(GameConfiguration) sequence_number = models.PositiveIntegerField() + def __unicode__(self): + return "Round # {0} for game {1} ".format(self.sequence_number, self.game_configuration) + # class Meta: # db_table = 'vcweb_round_configuration' @@ -372,6 +375,7 @@ ('string', 'String'), ('float', 'Float'), ('boolean', (('True', True), ('False', False))), + ('enum', 'enum') ) name = models.CharField(max_length=255) type = models.CharField(max_length=32, choices=PARAMETER_TYPES) @@ -411,7 +415,7 @@ # round parameters are class RoundParameter(models.Model): - round_configuration = models.ForeignKey(RoundConfiguration) + round_configuration = models.ForeignKey(RoundConfiguration, related_name='parameters') parameter = models.ForeignKey(ConfigurationParameter) parameter_value = models.CharField(max_length=255) @@ -442,7 +446,8 @@ class DataValue(models.Model): parameter = models.ForeignKey(DataParameter) parameter_value = models.CharField(max_length=255) - time_recorded = models.TimeField(auto_now_add=True) + # FIXME: change to DateTimeField + time_recorded = models.DateTimeField(auto_now_add=True) game_instance = models.ForeignKey(GameInstance) @staticmethod |