[virtualcommons-svn] commit/foraging: alllee: refactoring facilitator show logic, making it a bit m
Status: Beta
Brought to you by:
alllee
From: Bitbucket <com...@bi...> - 2011-09-30 11:12:50
|
1 new changeset in foraging: http://bitbucket.org/virtualcommons/foraging/changeset/bd991e6567ed/ changeset: bd991e6567ed user: alllee date: 2011-09-30 13:12:39 summary: refactoring facilitator show logic, making it a bit more generic. All ShowXXX requests now automatically pass through to the client w/o having to explicitly iterate and recreate them via the ShowRequest interface. affected #: 18 files (-1 bytes) --- a/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java Fri Sep 30 04:12:39 2011 -0700 @@ -385,11 +385,7 @@ } public String getSanctionInstructions() { - return getProperty("sanction-instructions", "<h2>Voting instructions</h2>" + - "<ul> " + - "<li> You must make a choice within the next 30 seconds. " + - "<li>The votes of all participants in your group will determine the outcome." + - "</ul>"); + return getProperty("sanction-instructions"); } public boolean isAlwaysInExplicitCollectionMode() { @@ -523,6 +519,10 @@ return getBooleanProperty("rotating-monitor-enabled", false); } + /** + * Returns true if voting is enabled before the beginning of this round. + * @return + */ public boolean isVotingEnabled() { return getBooleanProperty("voting-enabled"); } @@ -659,6 +659,10 @@ return getDoubleProperty("quiz-correct-answer-reward", getParentConfiguration().getQuizCorrectAnswerReward()); } + /** + * Returns true if we should have a survey at the beginning of this round. + * @return + */ public boolean isExternalSurveyEnabled() { return getBooleanProperty("external-survey-enabled"); } --- a/src/main/java/edu/asu/commons/foraging/event/ShowInstructionsRequest.java Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/event/ShowInstructionsRequest.java Fri Sep 30 04:12:39 2011 -0700 @@ -3,11 +3,17 @@ import edu.asu.commons.event.AbstractEvent; import edu.asu.commons.net.Identifier; -public class ShowInstructionsRequest extends AbstractEvent { +public class ShowInstructionsRequest extends AbstractEvent implements ShowRequest<ShowInstructionsRequest> { private static final long serialVersionUID = 3774308614796618926L; public ShowInstructionsRequest(Identifier id) { super(id); } + + @Override + public ShowInstructionsRequest copy(Identifier id) { + return new ShowInstructionsRequest(id); + } + } --- a/src/main/java/edu/asu/commons/foraging/event/ShowTrustGameRequest.java Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/event/ShowTrustGameRequest.java Fri Sep 30 04:12:39 2011 -0700 @@ -3,11 +3,16 @@ import edu.asu.commons.event.AbstractEvent; import edu.asu.commons.net.Identifier; -public class ShowTrustGameRequest extends AbstractEvent { +public class ShowTrustGameRequest extends AbstractEvent implements ShowRequest<ShowTrustGameRequest> { private static final long serialVersionUID = 3774308614796618926L; public ShowTrustGameRequest(Identifier id) { super(id); } + + @Override + public ShowTrustGameRequest copy(Identifier id) { + return new ShowTrustGameRequest(id); + } } --- a/src/main/java/edu/asu/commons/foraging/facilitator/Facilitator.java Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/facilitator/Facilitator.java Fri Sep 30 04:12:39 2011 -0700 @@ -22,7 +22,10 @@ import edu.asu.commons.foraging.event.FacilitatorUpdateEvent; import edu.asu.commons.foraging.event.QuizCompletedEvent; import edu.asu.commons.foraging.event.ShowInstructionsRequest; +import edu.asu.commons.foraging.event.ShowSurveyInstructionsRequest; import edu.asu.commons.foraging.event.ShowTrustGameRequest; +import edu.asu.commons.foraging.event.ShowVoteScreenRequest; +import edu.asu.commons.foraging.event.ShowVotingInstructionsRequest; import edu.asu.commons.foraging.event.TrustGameSubmissionEvent; import edu.asu.commons.foraging.model.ServerDataModel; @@ -106,44 +109,6 @@ } } - // public void accept(Identifier id, Object event) { - // if (event instanceof ConfigurationEvent) { - // ConfigurationEvent configEvent = (ConfigurationEvent) event; - // setConfiguration(configEvent.getConfiguration()); - // } - // else if (event instanceof ServerGameStateEvent) { - // ServerGameStateEvent serverGameStateEvent = (ServerGameStateEvent) event; - // if (!stopExperiment) { - // - // if (serverGameState == null) { - // System.err.println("about to display game.."); - // experimentRunning = true; - // // FIXME: could use configuration from this event... serverGameStateEvent.getServerGameState().getConfiguration(); - // serverGameState = serverGameStateEvent.getServerGameState(); - // facilitatorWindow.displayGame(); - // } - // else { - // // synchronous updates - // serverGameState = serverGameStateEvent.getServerGameState(); - // } - // } - // facilitatorWindow.updateWindow(serverGameStateEvent.getTimeLeft()); - // // facilitatorWindow.repaint(); - // } - // else if (event instanceof FacilitatorEndRoundEvent) { - // FacilitatorEndRoundEvent endRoundEvent = (FacilitatorEndRoundEvent) event; - // serverGameState = null; - // facilitatorWindow.endRound(endRoundEvent); - // } - // else if (event instanceof FacilitatorSanctionUpdateEvent) { - // FacilitatorSanctionUpdateEvent fdue = (FacilitatorSanctionUpdateEvent) event; - // facilitatorWindow.updateDebriefing(fdue); - // } - // else if (event instanceof QuizCompletedEvent) { - // facilitatorWindow.quizCompleted(); - // } - // } - /* * Send a request to server to start an experiment */ @@ -159,9 +124,22 @@ transmit(new ShowInstructionsRequest(getId())); } - void sendShowTrustGameRequest() { + public void sendShowTrustGameRequest() { transmit(new ShowTrustGameRequest(getId())); } + + + public void sendShowVotingInstructionsRequest() { + transmit(new ShowVotingInstructionsRequest(getId())); + } + + public void sendShowVoteScreenRequest() { + transmit(new ShowVoteScreenRequest(getId())); + } + + public void sendShowSurveyInstructionsRequest() { + transmit(new ShowSurveyInstructionsRequest(getId())); + } /* * Send a request to start a round @@ -246,4 +224,5 @@ public void setServerGameState(ServerDataModel serverGameState) { this.serverDataModel = serverGameState; } + } --- a/src/main/java/edu/asu/commons/foraging/facilitator/FacilitatorWindow.java Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/facilitator/FacilitatorWindow.java Fri Sep 30 04:12:39 2011 -0700 @@ -62,6 +62,9 @@ private JMenuItem startChatMenuItem; private JMenuItem showTrustGameMenuItem; + private JMenuItem showVotingInstructionsMenuItem; + private JMenuItem showVoteScreenMenuItem; + private JMenuItem showSurveyInstructionsMenuItem; private HtmlEditorPane messageEditorPane; @@ -138,6 +141,8 @@ } }); menu.add(showTrustGameMenuItem); + + startRoundMenuItem = new JMenuItem("Start"); startRoundMenuItem.setMnemonic(KeyEvent.VK_T); @@ -159,6 +164,30 @@ }); menu.add(stopRoundMenuItem); menuBar.add(menu); + + // voting menu + menu = new JMenu("Voting"); + + showVotingInstructionsMenuItem = createMenuItem(menu, "Show voting instructions", new ActionListener() { + public void actionPerformed(ActionEvent e) { + facilitator.sendShowVotingInstructionsRequest(); + } + }); + showVoteScreenMenuItem = createMenuItem(menu, "Show voting screen", new ActionListener() { + public void actionPerformed(ActionEvent e) { + facilitator.sendShowVoteScreenRequest(); + } + }); + menuBar.add(menu); + + // survey menu + menu = new JMenu("Survey"); + showSurveyInstructionsMenuItem = createMenuItem(menu, "Show survey instructions", new ActionListener() { + public void actionPerformed(ActionEvent e) { + facilitator.sendShowSurveyInstructionsRequest(); + } + }); + menuBar.add(menu); //Configuration menu menu = new JMenu("Configuration"); @@ -176,6 +205,13 @@ return menuBar; } + + private JMenuItem createMenuItem(JMenu menu, String name, ActionListener listener) { + JMenuItem menuItem = new JMenuItem(name); + menuItem.addActionListener(listener); + menu.add(menuItem); + return menuItem; + } public JMenuBar getMenuBar() { return menuBar; --- a/src/main/java/edu/asu/commons/foraging/jcal3d/core/CoreModel.java Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/jcal3d/core/CoreModel.java Fri Sep 30 04:12:39 2011 -0700 @@ -5,7 +5,6 @@ import java.util.Vector; import edu.asu.commons.foraging.graphics.RGBA; -import edu.asu.commons.foraging.jcal3d.misc.Error; import edu.asu.commons.foraging.jcal3d.misc.Loader; import edu.asu.commons.foraging.jcal3d.misc.Saver; --- a/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java Fri Sep 30 04:12:39 2011 -0700 @@ -57,6 +57,7 @@ import edu.asu.commons.foraging.event.RoundStartedEvent; import edu.asu.commons.foraging.event.SanctionAppliedEvent; import edu.asu.commons.foraging.event.ShowInstructionsRequest; +import edu.asu.commons.foraging.event.ShowRequest; import edu.asu.commons.foraging.event.ShowTrustGameRequest; import edu.asu.commons.foraging.event.SurveyIdSubmissionRequest; import edu.asu.commons.foraging.event.SynchronizeClientEvent; @@ -535,33 +536,46 @@ } } }); - addEventProcessor(new EventTypeProcessor<ShowInstructionsRequest>(ShowInstructionsRequest.class) { - public void handle(ShowInstructionsRequest event) { - // FIXME: assign groups? - if (event.getId().equals(facilitatorId)) { - logger.info("Show Instructions request from facilitator - showing round instructions."); - for (Identifier id : clients.keySet()) { - transmit(new ShowInstructionsRequest(id)); + addEventProcessor(new EventTypeProcessor<ShowRequest>(ShowRequest.class, true) { + public void handle(ShowRequest request) { + if (request.getId().equals(facilitatorId)) { + logger.info("handling request " + request + " from facilitator"); + for (Identifier id: clients.keySet()) { + transmit(request.copy(id)); } } else { - logger.warning("Ignoring show instructions request from id: " + event.getId()); + sendFacilitatorMessage("Ignoring show request from id: " + request.getId()); } } }); - addEventProcessor(new EventTypeProcessor<ShowTrustGameRequest>(ShowTrustGameRequest.class) { - public void handle(ShowTrustGameRequest event) { - if (event.getId().equals(facilitatorId)) { - logger.info("Showing trust game."); - for (Identifier id : clients.keySet()) { - transmit(new ShowTrustGameRequest(id)); - } - } - else { - logger.warning("Ignoring show instructions request from id: " + event.getId()); - } - } - }); +// addEventProcessor(new EventTypeProcessor<ShowInstructionsRequest>(ShowInstructionsRequest.class) { +// public void handle(ShowInstructionsRequest event) { +// // FIXME: assign groups? +// if (event.getId().equals(facilitatorId)) { +// logger.info("Show Instructions request from facilitator - showing round instructions."); +// for (Identifier id : clients.keySet()) { +// transmit(new ShowInstructionsRequest(id)); +// } +// } +// else { +// logger.warning("Ignoring show instructions request from id: " + event.getId()); +// } +// } +// }); +// addEventProcessor(new EventTypeProcessor<ShowTrustGameRequest>(ShowTrustGameRequest.class) { +// public void handle(ShowTrustGameRequest event) { +// if (event.getId().equals(facilitatorId)) { +// logger.info("Showing trust game."); +// for (Identifier id : clients.keySet()) { +// transmit(new ShowTrustGameRequest(id)); +// } +// } +// else { +// logger.warning("Ignoring show instructions request from id: " + event.getId()); +// } +// } +// }); addEventProcessor(new EventTypeProcessor<BeginRoundRequest>(BeginRoundRequest.class) { public void handle(BeginRoundRequest event) { if (event.getId().equals(facilitatorId)) { --- a/src/main/java/edu/asu/commons/foraging/ui/GameWindow2D.java Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/ui/GameWindow2D.java Fri Sep 30 04:12:39 2011 -0700 @@ -785,9 +785,10 @@ getPanel().remove(chatPanel); chatPanel = null; } - if (dataModel.getRoundConfiguration().isPostRoundSanctioningEnabled()) { + RoundConfiguration roundConfiguration = dataModel.getRoundConfiguration(); + if (roundConfiguration.isPostRoundSanctioningEnabled()) { // add sanctioning text and slap the PostRoundSanctioningPanel in - PostRoundSanctioningPanel panel = new PostRoundSanctioningPanel(event, dataModel.getRoundConfiguration(), client); + PostRoundSanctioningPanel panel = new PostRoundSanctioningPanel(event, roundConfiguration, client); panel.setName(POST_ROUND_SANCTIONING_PANEL_NAME); add(panel); showPanel(POST_ROUND_SANCTIONING_PANEL_NAME); --- a/src/main/java/edu/asu/commons/foraging/ui/TrustGamePanel.java Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/ui/TrustGamePanel.java Fri Sep 30 04:12:39 2011 -0700 @@ -1,21 +1,19 @@ package edu.asu.commons.foraging.ui; import java.awt.Component; -import java.util.Arrays; +import javax.swing.ButtonModel; import javax.swing.DefaultCellEditor; import javax.swing.JComboBox; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableColumn; import javax.swing.table.TableModel; import edu.asu.commons.foraging.client.ForagingClient; import edu.asu.commons.foraging.conf.RoundConfiguration; -import javax.sound.midi.SysexMessage; -import javax.swing.ButtonModel; -import javax.swing.table.TableColumn; /** * $Id:$ --- a/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round4.xml Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round4.xml Fri Sep 30 04:12:39 2011 -0700 @@ -31,6 +31,7 @@ ]]></entry> + <entry key='voting-instructions'><![CDATA[ <h1>Voting Instructions</h1> @@ -52,6 +53,25 @@ ]]></entry> + +<entry key="instructions"> +<![CDATA[ +<h3>Round 4 Instructions</h3> +<hr> +<p> + Round 4 is about to begin. +</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='external-survey-enabled'>true</entry><entry key='survey-instructions'><![CDATA[ @@ -77,22 +97,45 @@ ]]></entry> -<entry key="instructions"> -<![CDATA[ -<h3>Round 4 Instructions</h3> + +<entry key='sanction-type'>REAL_TIME</entry> +<entry key="sanction-cost">1</entry> +<entry key="sanction-multiplier">2</entry> +<entry key='sanction-instructions'> + <![CDATA[ + <h1>Instructions</h1> + <hr> +<p> +During this upcoming round you will have the option to reduce the earnings of +another participant at a cost to your own earnings. +</p> +<h2>How it works</h2><hr> -<p> - Round 4 is about to begin. -</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> -]]> + <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> + <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> + <li>If your tokens are being reduced or you are reducing another participant's + tokens, you will receive some visual cues. When your tokens are being reduced + your yellow dot will turn red briefly with a blue background. The participant + currently reducing your tokens will turn purple with a white background. + </li> + <li>You may reduce the earnings of 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>. + </li> + </ul> + ]]></entry></properties> --- a/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round5.xml Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round5.xml Fri Sep 30 04:12:39 2011 -0700 @@ -28,23 +28,44 @@ </p> ]]></entry> -<entry key="chat-instructions"> -<![CDATA[ + +<entry key='sanction-type'>REAL_TIME</entry> +<entry key="sanction-cost">1</entry> +<entry key="sanction-multiplier">2</entry> +<entry key='sanction-instructions'> + <![CDATA[ + <h1>Instructions</h1> + <hr><p> -You can chat with the other participants in your group during this 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. +During this upcoming round you will have the option to reduce the earnings of +another participant at a cost to your own earnings. </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 and pressing the -enter key. -</p> -]]> +<h2>How it works</h2> +<hr> + <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> + <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> + <li>If your tokens are being reduced or you are reducing another participant's + tokens, you will receive some visual cues. When your tokens are being reduced + your yellow dot will turn red briefly with a blue background. The participant + currently reducing your tokens will turn purple with a white background. + </li> + <li>You may reduce the earnings of 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>. + </li> + </ul> + ]]></entry></properties> --- a/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round6.xml Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round6.xml Fri Sep 30 04:12:39 2011 -0700 @@ -8,14 +8,75 @@ <entry key="resource-width">26</entry><entry key="duration">240</entry> -<entry key='tokens-field-of-vision'>true</entry> -<entry key='subjects-field-of-vision'>true</entry> - <entry key="initial-distribution">.25</entry><entry key='always-explicit'>true</entry><entry key='max-cell-occupancy'>1</entry> +<entry key='sanction-type'>REAL_TIME</entry> +<entry key="sanction-cost">1</entry> +<entry key="sanction-multiplier">2</entry> +<entry key='sanction-instructions'> + <![CDATA[ + <h1>Instructions</h1> + <hr> +<p> +During this upcoming round you will have the option to reduce the earnings of +another participant at a cost to your own earnings. +</p> +<h2>How it works</h2> +<hr> + <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> + <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> + <li>If your tokens are being reduced or you are reducing another participant's + tokens, you will receive some visual cues. When your tokens are being reduced + your yellow dot will turn red briefly with a blue background. The participant + currently reducing your tokens will turn purple with a white background. + </li> + <li>You may reduce the earnings of 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>. + </li> + </ul> + ]]> +</entry> +<entry key='external-survey-enabled'>true</entry> +<entry key='survey-instructions'> + <![CDATA[ + <h1>Survey</h1> + <hr> + <p> + Before we continue to the next round of the token task, we would like to ask you + some quick questions. At the beginning of the survey you will need to enter: + </p> + <ul> + <li>Your player ID: {participantId} </li> + <li>Your survey ID: {surveyId} </li> + </ul> + <p> + Please <a href='{surveyLink}'>click here</a> to begin the survey. + </p> + ]]> +</entry> + +<entry key='survey-link'> + <![CDATA[ + https://qtrial.qualtrics.com/SE/?SID=SV_38lReBOv0Wk7wgY + ]]> +</entry> + <entry key="instructions"><![CDATA[ --- a/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round7.xml Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round7.xml Fri Sep 30 04:12:39 2011 -0700 @@ -8,9 +8,6 @@ <entry key="resource-width">26</entry><entry key="duration">240</entry> -<entry key='tokens-field-of-vision'>true</entry> -<entry key='subjects-field-of-vision'>true</entry> - <entry key="initial-distribution">.25</entry><entry key='always-explicit'>true</entry> --- a/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round9.xml Thu Sep 29 19:48:30 2011 -0700 +++ b/src/main/resources/configuration/indiana-experiments/fall-2011/pretest/round9.xml Fri Sep 30 04:12:39 2011 -0700 @@ -17,12 +17,38 @@ <entry key='max-cell-occupancy'>1</entry> +<entry key='external-survey-enabled'>true</entry> +<entry key='survey-instructions'> + <![CDATA[ + <h1>Survey</h1> + <hr> + <p> + Before we continue to the next round of the token task, we would like to ask you + some quick questions. At the beginning of the survey you will need to enter: + </p> + <ul> + <li>Your player ID: {participantId} </li> + <li>Your survey ID: {surveyId} </li> + </ul> + <p> + Please <a href='{surveyLink}'>click here</a> to begin the survey. + </p> + ]]> +</entry> + +<entry key='survey-link'> + <![CDATA[ + https://qtrial.qualtrics.com/SE/?SID=SV_38lReBOv0Wk7wgY + ]]> +</entry> + + <entry key="instructions"><![CDATA[ <h3>Instructions</h3><hr><p> -The length of this round is again four minutes. + This is the last round of the experiment. </p><p> If you have any questions please raise your hand. <b>Do you have any Repository URL: https://bitbucket.org/virtualcommons/foraging/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |