[virtualcommons-svn] commit/irrigation: alllee: animation appears to be mostly working now, with on
Status: Beta
Brought to you by:
alllee
From: Bitbucket <com...@bi...> - 2012-02-21 21:58:16
|
1 new commit in irrigation: https://bitbucket.org/virtualcommons/irrigation/changeset/a2a5b61d5434/ changeset: a2a5b61d5434 user: alllee date: 2012-02-21 22:58:07 summary: animation appears to be mostly working now, with one glitch for position A when their gate is open affected #: 7 files diff -r 7bc24ad24c424230a11db6637311436713a0d31d -r a2a5b61d5434c9c3a4dd37a6b0aa186c6326d0c8 src/main/java/edu/asu/commons/irrigation/client/CanalPanel.java --- a/src/main/java/edu/asu/commons/irrigation/client/CanalPanel.java +++ b/src/main/java/edu/asu/commons/irrigation/client/CanalPanel.java @@ -17,7 +17,7 @@ /** * $Id$ * - * FIXME: completely rewrite horrifyingly convoluted animation logic + * FIXME: convoluted gate and animation logic is in dire need of refactoring / rewrite * * @author Sanket Joshi, Allen Lee */ @@ -30,7 +30,7 @@ private final static int DELAY = 20; - private Ball[] balls; + private Ball[] particles; private final static int BALLCOUNT = 500; private final static int NUMBER_OF_GATES = 6; @@ -104,11 +104,7 @@ graphics2D.fillRect(gates[i].getX(), gates[i].getY(), gates[i].getWidth(), gates[i].getHeight()); } - // checkRestrictedVisibility(); for (ClientData clientData : sortedClientDataList) { -// if (restrictedVisibility && !clientDataModel.isImmediateNeighbor(clientData)) { -// continue; -// } int priority = clientData.getPriority(); Gate gate = gates[priority]; graphics2D.setColor(Color.BLUE); @@ -127,22 +123,22 @@ graphics.setColor(Color.WHITE); // int ballCounter = 0; for (int i = 0; i < BALLCOUNT; i++) { - if ((balls[i].getPosition() == 1) || (balls[i].getPosition() == 2) - || (balls[i].getPosition() == 3) - || (balls[i].getPosition() == 4) - || (balls[i].getPosition() == 5)) { - if (!((gates[balls[i].getPosition() - 1].isClosed()) - && balls[i].getY() >= (gates[balls[i].getPosition() - 1].getY() + gates[balls[i].getPosition() - 1].getHeight()))) - graphics.fillOval(balls[i].x, balls[i].y, - balls[i].getBallSize(), balls[i].getBallSize()); + if ((particles[i].getPosition() == 1) || (particles[i].getPosition() == 2) + || (particles[i].getPosition() == 3) + || (particles[i].getPosition() == 4) + || (particles[i].getPosition() == 5)) { + if (!((gates[particles[i].getPosition() - 1].isClosed()) + && particles[i].getY() >= (gates[particles[i].getPosition() - 1].getY() + gates[particles[i].getPosition() - 1].getHeight()))) + graphics.fillOval(particles[i].x, particles[i].y, + particles[i].getBallSize(), particles[i].getBallSize()); } else { - if (balls[i].getPosition() != 0) { - if (gates[balls[i].getPosition() - 6].getHeight() != 0) - graphics.fillOval(balls[i].x, balls[i].y, - balls[i].getBallSize(), balls[i].getBallSize()); + if (particles[i].getPosition() != 0) { + if (gates[particles[i].getPosition() - 6].getHeight() != 0) + graphics.fillOval(particles[i].x, particles[i].y, + particles[i].getBallSize(), particles[i].getBallSize()); } else { - graphics.fillOval(balls[i].x, balls[i].y, - balls[i].getBallSize(), balls[i].getBallSize()); + graphics.fillOval(particles[i].x, particles[i].y, + particles[i].getBallSize(), particles[i].getBallSize()); } } } @@ -233,9 +229,9 @@ * initialize the Balls */ private void initializeBalls() { - balls = new Ball[BALLCOUNT]; + particles = new Ball[BALLCOUNT]; for (int i = 0; i < BALLCOUNT; i++) { - balls[i] = new Ball(generator); + particles[i] = new Ball(generator); } } @@ -246,8 +242,8 @@ ClientData thisClientData = clientDataModel.getClientData(); for (int i = 0; i < BALLCOUNT; i++) { // updateGUI(); - balls[i].x += balls[i].moveX; - balls[i].y += balls[i].moveY; + particles[i].x += particles[i].moveX; + particles[i].y += particles[i].moveY; process(i, sortedClients, thisClientData); } repaint(); @@ -259,40 +255,40 @@ */ private void process(int i, List<ClientData> sortedClients, ClientData thisClientData) { - switch (balls[i].getPosition()) { + switch (particles[i].getPosition()) { case 0: - if ((balls[i].x >= (reservoirWidth - gateBuffer) && balls[i].x <= reservoirWidth) - && (balls[i].y >= reservoirHeight - (int) (maximumIrrigationCapacity * canalHeightMultiplier) && balls[i].y <= reservoirHeight)) + if ((particles[i].x >= (reservoirWidth - gateBuffer) && particles[i].x <= reservoirWidth) + && (particles[i].y >= reservoirHeight - (int) (maximumIrrigationCapacity * canalHeightMultiplier) && particles[i].y <= reservoirHeight)) { - balls[i].setPosition(1); + particles[i].setPosition(1); setBounds(i); } // still in server else { setBounds(i); - if (balls[i].x <= balls[i].xLowerBound - || balls[i].x >= balls[i].xUpperBound - - balls[i].getBallSize()) { - balls[i].moveX = balls[i].moveX * -1; + if (particles[i].x <= particles[i].xLowerBound + || particles[i].x >= particles[i].xUpperBound + - particles[i].getBallSize()) { + particles[i].moveX = particles[i].moveX * -1; } - if (balls[i].y <= balls[i].yLowerBound - || balls[i].y >= balls[i].yUpperBound - - balls[i].getBallSize()) - balls[i].moveY = balls[i].moveY * -1; + if (particles[i].y <= particles[i].yLowerBound + || particles[i].y >= particles[i].yUpperBound + - particles[i].getBallSize()) + particles[i].moveY = particles[i].moveY * -1; } break; case 1: if (gates[0].isOpen() - && (balls[i].x >= gates[0].getOpeningsX() && balls[i].x <= (gates[0].getOpeningsX() + gateBuffer)) - && (balls[i].y >= reservoirHeight - gateBuffer && balls[i].y <= reservoirHeight)) + && (particles[i].x >= gates[0].getOpeningsX() && particles[i].x <= (gates[0].getOpeningsX() + gateBuffer)) + && (particles[i].y >= reservoirHeight - gateBuffer && particles[i].y <= reservoirHeight)) { if (restrictedVisibility && sortedClients.get(0).isImmediateNeighbor(thisClientData) || ! restrictedVisibility) { // if we are in the restricted visibility condition AND gate 0 is an immediate neighbor of this client OR we are not in a restricted visibility condition at all, put this ball in the // gate (or at least I *think* this is what Sanket's god-awful code is doing). - balls[i].setPosition(7); + particles[i].setPosition(7); // directly pass in the information setBounds(i); break; @@ -300,190 +296,189 @@ } // otherwise the gate is closed or we don't know enough about the gate, pass it on down setBounds(i); - if (balls[i].getX() > balls[i].xUpperBound) { - balls[i].setPosition(2); + if (particles[i].getX() > particles[i].xUpperBound) { + particles[i].setPosition(2); } - if (balls[i].getY() >= balls[i].yUpperBound - - balls[i].getBallSize() - || balls[i].getY() <= balls[i].yLowerBound) { - balls[i].moveY = balls[i].moveY * -1; + if (particles[i].getY() >= particles[i].yUpperBound + - particles[i].getBallSize() + || particles[i].getY() <= particles[i].yLowerBound) { + particles[i].moveY = particles[i].moveY * -1; } break; case 2: if (gates[1].isOpen() - && (balls[i].x >= gates[1].getOpeningsX() && balls[i].x <= (gates[1] + && (particles[i].x >= gates[1].getOpeningsX() && particles[i].x <= (gates[1] .getOpeningsX() + gateBuffer)) - && (balls[i].y >= reservoirHeight - gateBuffer && balls[i].y <= reservoirHeight)) + && (particles[i].y >= reservoirHeight - gateBuffer && particles[i].y <= reservoirHeight)) { if (!restrictedVisibility || (restrictedVisibility && sortedClients.get(1).isImmediateNeighbor(thisClientData))) { - balls[i].setPosition(8); + particles[i].setPosition(8); // directly pass in the information setBounds(i); break; } } setBounds(i); - if (balls[i].getX() > balls[i].xUpperBound) { - balls[i].setPosition(3); + if (particles[i].getX() > particles[i].xUpperBound) { + particles[i].setPosition(3); } - if (balls[i].getY() >= balls[i].yUpperBound - - balls[i].getBallSize() - || balls[i].getY() <= balls[i].yLowerBound) { - balls[i].moveY = balls[i].moveY * -1; + if (particles[i].getY() >= particles[i].yUpperBound + - particles[i].getBallSize() + || particles[i].getY() <= particles[i].yLowerBound) { + particles[i].moveY = particles[i].moveY * -1; } break; case 3: if (gates[2].isOpen() - && (balls[i].x >= gates[2].getOpeningsX() && balls[i].x <= (gates[2] + && (particles[i].x >= gates[2].getOpeningsX() && particles[i].x <= (gates[2] .getOpeningsX() + gateBuffer)) - && (balls[i].y >= reservoirHeight - gateBuffer && balls[i].y <= reservoirHeight)) + && (particles[i].y >= reservoirHeight - gateBuffer && particles[i].y <= reservoirHeight)) { if (!restrictedVisibility || (restrictedVisibility && sortedClients.get(2).isImmediateNeighbor(thisClientData))) { - balls[i].setPosition(9); + particles[i].setPosition(9); // directly pass in the information setBounds(i); break; } } setBounds(i); - if (balls[i].getX() > balls[i].xUpperBound) { - balls[i].setPosition(4); + if (particles[i].getX() > particles[i].xUpperBound) { + particles[i].setPosition(4); } - if (balls[i].getY() >= balls[i].yUpperBound - - balls[i].getBallSize() - || balls[i].getY() <= balls[i].yLowerBound) { - balls[i].moveY = balls[i].moveY * -1; + if (particles[i].getY() >= particles[i].yUpperBound + - particles[i].getBallSize() + || particles[i].getY() <= particles[i].yLowerBound) { + particles[i].moveY = particles[i].moveY * -1; } break; case 4: if (gates[3].isOpen() - && (balls[i].x >= gates[3].getOpeningsX() && balls[i].x <= (gates[3] + && (particles[i].x >= gates[3].getOpeningsX() && particles[i].x <= (gates[3] .getOpeningsX() + gateBuffer)) - && (balls[i].y >= reservoirHeight - gateBuffer && balls[i].y <= reservoirHeight)) + && (particles[i].y >= reservoirHeight - gateBuffer && particles[i].y <= reservoirHeight)) { if (!restrictedVisibility || (restrictedVisibility && !sortedClients.get(3).isImmediateNeighbor(thisClientData))) { - balls[i].setPosition(10); + particles[i].setPosition(10); // directly pass in the information setBounds(i); break; } } setBounds(i); - if (balls[i].getX() > balls[i].xUpperBound) { - balls[i].setPosition(5); + if (particles[i].getX() > particles[i].xUpperBound) { + particles[i].setPosition(5); } - if (balls[i].getY() >= balls[i].yUpperBound - - balls[i].getBallSize() - || balls[i].getY() <= balls[i].yLowerBound) { - balls[i].moveY = balls[i].moveY * -1; + if (particles[i].getY() >= particles[i].yUpperBound + - particles[i].getBallSize() + || particles[i].getY() <= particles[i].yLowerBound) { + particles[i].moveY = particles[i].moveY * -1; } break; case 5: if (gates[4].isOpen() - && (balls[i].x >= gates[4].getOpeningsX() && balls[i].x <= (gates[4] + && (particles[i].x >= gates[4].getOpeningsX() && particles[i].x <= (gates[4] .getOpeningsX() + gateBuffer)) - && (balls[i].y >= reservoirHeight - gateBuffer && balls[i].y <= reservoirHeight)) + && (particles[i].y >= reservoirHeight - gateBuffer && particles[i].y <= reservoirHeight)) { if (!restrictedVisibility || (restrictedVisibility && !sortedClients.get(4).isImmediateNeighbor(thisClientData))) { - balls[i].setPosition(11); + particles[i].setPosition(11); // directly pass in the information setBounds(i); break; } } setBounds(i); - if (balls[i].getX() > balls[i].xUpperBound) { - balls[i].setPosition(6); + if (particles[i].getX() > particles[i].xUpperBound) { + particles[i].setPosition(6); } - if (balls[i].getY() >= balls[i].yUpperBound - - balls[i].getBallSize() - || balls[i].getY() <= balls[i].yLowerBound) { - balls[i].moveY = balls[i].moveY * -1; + if (particles[i].getY() >= particles[i].yUpperBound + - particles[i].getBallSize() + || particles[i].getY() <= particles[i].yLowerBound) { + particles[i].moveY = particles[i].moveY * -1; } break; case 6: setBounds(i); - if (balls[i].getX() > balls[i].xUpperBound) { - setBallInServer(i); + if (particles[i].getX() > particles[i].xUpperBound) { + returnParticleToReservoir(i); } - if (balls[i].getY() >= balls[i].yUpperBound - - balls[i].getBallSize() - || balls[i].getY() <= balls[i].yLowerBound) { - balls[i].moveY = balls[i].moveY * -1; + if (particles[i].getY() >= particles[i].yUpperBound + - particles[i].getBallSize() + || particles[i].getY() <= particles[i].yLowerBound) { + particles[i].moveY = particles[i].moveY * -1; } break; } // set balls back to the server when they complete their flow in the // gates - if ((balls[i].getPosition() == 11) || (balls[i].getPosition() == 7) - || (balls[i].getPosition() == 8) - || (balls[i].getPosition() == 9) - || (balls[i].getPosition() == 10)) { - if (balls[i].getY() >= 150) { - setBallInServer(i); + if ((particles[i].getPosition() == 11) || (particles[i].getPosition() == 7) + || (particles[i].getPosition() == 8) + || (particles[i].getPosition() == 9) + || (particles[i].getPosition() == 10)) { + if (particles[i].getY() >= 150) { + returnParticleToReservoir(i); } else { setBounds(i); } } } - private void setBallInServer(int i) { + private void returnParticleToReservoir(int i) { generator.setSeed(i * (i + 1)); - balls[i].setX(generator.nextInt(reservoirWidth)); - balls[i].setY(generator.nextInt(reservoirHeight)); - balls[i].setPosition(0); - if (balls[i].moveX == 0) - balls[i].moveX = generator.nextInt(15); + particles[i].setX(generator.nextInt(reservoirWidth)); + particles[i].setY(generator.nextInt(reservoirHeight)); + particles[i].setPosition(0); + if (particles[i].moveX == 0) + particles[i].moveX = generator.nextInt(15); setBounds(i); } - private void setBounds(int ballIndex) { - // TODO Auto-generated method stub + private void setBounds(int index) { // ball is in the server - if (balls[ballIndex].getPosition() == 0) { - balls[ballIndex].xUpperBound = reservoirWidth; - balls[ballIndex].xLowerBound = 0; - balls[ballIndex].yUpperBound = reservoirHeight; - balls[ballIndex].yLowerBound = 0; + if (particles[index].getPosition() == 0) { + particles[index].xUpperBound = reservoirWidth; + particles[index].xLowerBound = 0; + particles[index].yUpperBound = reservoirHeight; + particles[index].yLowerBound = 0; // balls[ballIndex].moveX = generator.nextInt(6); // balls[ballIndex].moveY = generator.nextInt(6); // balls[ballIndex].moveX = 3; // balls[ballIndex].moveY = 3; } else { - if ((balls[ballIndex].getPosition() == 1) - || (balls[ballIndex].getPosition() == 2) - || (balls[ballIndex].getPosition() == 3) - || (balls[ballIndex].getPosition() == 4) - || (balls[ballIndex].getPosition() == 5) - || (balls[ballIndex].getPosition() == 6)) { + if ((particles[index].getPosition() == 1) + || (particles[index].getPosition() == 2) + || (particles[index].getPosition() == 3) + || (particles[index].getPosition() == 4) + || (particles[index].getPosition() == 5) + || (particles[index].getPosition() == 6)) { - balls[ballIndex].xUpperBound = gates[balls[ballIndex].getPosition() - 1].getX() - + gates[balls[ballIndex].getPosition() - 1].getWidth(); - balls[ballIndex].xLowerBound = gates[balls[ballIndex].getPosition() - 1].getX(); - balls[ballIndex].yUpperBound = gates[balls[ballIndex].getPosition() - 1].getY() + particles[index].xUpperBound = gates[particles[index].getPosition() - 1].getX() + + gates[particles[index].getPosition() - 1].getWidth(); + particles[index].xLowerBound = gates[particles[index].getPosition() - 1].getX(); + particles[index].yUpperBound = gates[particles[index].getPosition() - 1].getY() /* * +gate[balls[ballIndex]. * getPosition() - * 1].getHeight() */; - balls[ballIndex].yLowerBound = gates[balls[ballIndex].getPosition() - 1].getY(); + particles[index].yLowerBound = gates[particles[index].getPosition() - 1].getY(); } // the ball is in one of the openings else { - balls[ballIndex].xUpperBound = gates[balls[ballIndex] + particles[index].xUpperBound = gates[particles[index] .getPosition() - 7].getOpeningsX() - + gates[balls[ballIndex].getPosition() - 7].getGateWidth(); - balls[ballIndex].xLowerBound = gates[balls[ballIndex].getPosition() - 7].getOpeningsX(); - balls[ballIndex].yUpperBound = gates[balls[ballIndex].getPosition() - 7].getOpeningsY() - + gates[balls[ballIndex].getPosition() - 7].getOpeningsHeight(); - balls[ballIndex].yLowerBound = gates[balls[ballIndex].getPosition() - 7].getOpeningsY(); + + gates[particles[index].getPosition() - 7].getGateWidth(); + particles[index].xLowerBound = gates[particles[index].getPosition() - 7].getOpeningsX(); + particles[index].yUpperBound = gates[particles[index].getPosition() - 7].getOpeningsY() + + gates[particles[index].getPosition() - 7].getOpeningsHeight(); + particles[index].yLowerBound = gates[particles[index].getPosition() - 7].getOpeningsY(); // X change in motion - balls[ballIndex].moveX = 0; + particles[index].moveX = 0; // Y change in motion - balls[ballIndex].moveY = 3; + particles[index].moveY = 3; } } } diff -r 7bc24ad24c424230a11db6637311436713a0d31d -r a2a5b61d5434c9c3a4dd37a6b0aa186c6326d0c8 src/main/java/edu/asu/commons/irrigation/client/ExperimentGameWindow.java --- a/src/main/java/edu/asu/commons/irrigation/client/ExperimentGameWindow.java +++ b/src/main/java/edu/asu/commons/irrigation/client/ExperimentGameWindow.java @@ -585,7 +585,6 @@ SwingUtilities.invokeLater(new Runnable() { public void run() { startTimer(getServerConfiguration().getChatDuration() * 1000L); -// ChatPanel chatPanel = getChatPanel(); chatPanel.initialize(clientDataModel.getAllClientIdentifiers()); addCenterComponent( chatPanel ); chatPanel.setFocusInChatField(); diff -r 7bc24ad24c424230a11db6637311436713a0d31d -r a2a5b61d5434c9c3a4dd37a6b0aa186c6326d0c8 src/main/java/edu/asu/commons/irrigation/client/GamePanel.java --- a/src/main/java/edu/asu/commons/irrigation/client/GamePanel.java +++ b/src/main/java/edu/asu/commons/irrigation/client/GamePanel.java @@ -396,9 +396,14 @@ // FIXME: figure out how to reliably set the progress bar colors regardless of OS. // setProgressBarColor(timeLeft); // only show open gates for immediately neighboring clients. + boolean restrictedVisibility = clientDataModel.getRoundConfiguration().isRestrictedVisibility(); + final ClientData thisClientData = clientDataModel.getClientData(); for (final ClientData clientData : clientDataModel.getClientDataMap().values()) { if (clientData.isGateOpen()) { + if (restrictedVisibility && ! thisClientData.isImmediateNeighbor(clientData)) { + continue; + } canalPanel.openGate(clientData.getPriority()); } else { diff -r 7bc24ad24c424230a11db6637311436713a0d31d -r a2a5b61d5434c9c3a4dd37a6b0aa186c6326d0c8 src/main/java/edu/asu/commons/irrigation/client/IrrigationClient.java --- a/src/main/java/edu/asu/commons/irrigation/client/IrrigationClient.java +++ b/src/main/java/edu/asu/commons/irrigation/client/IrrigationClient.java @@ -158,6 +158,8 @@ RoundConfiguration configuration = event.getRoundConfiguration(); clientDataModel.setGroupDataModel(event.getClientData().getGroupDataModel()); clientDataModel.setRoundConfiguration(configuration); + // FIXME: will need to replace this with an explicit ShowInstructionsRequest if we end up needing + // explicit last-round show exit instructions behavior experimentGameWindow.updateRoundInstructions(configuration); } }); diff -r 7bc24ad24c424230a11db6637311436713a0d31d -r a2a5b61d5434c9c3a4dd37a6b0aa186c6326d0c8 src/main/java/edu/asu/commons/irrigation/client/TokenContributionChartPanel.java --- a/src/main/java/edu/asu/commons/irrigation/client/TokenContributionChartPanel.java +++ b/src/main/java/edu/asu/commons/irrigation/client/TokenContributionChartPanel.java @@ -98,7 +98,7 @@ private JFreeChart createBarChart(ClientDataModel clientDataModel) { final CategoryDataset dataset = createCategoryDataset(clientDataModel); - JFreeChart chart = ChartFactory.createBarChart("Tokens Contributed by your Neighbors", "Participant", "Tokens Invested", dataset, + JFreeChart chart = ChartFactory.createBarChart("Tokens Invested by You and Your Neighbors", "Participant", "Tokens Invested", dataset, PlotOrientation.VERTICAL, false, false, false); CategoryPlot plot = chart.getCategoryPlot(); ValueAxis rangeAxis = plot.getRangeAxis(); diff -r 7bc24ad24c424230a11db6637311436713a0d31d -r a2a5b61d5434c9c3a4dd37a6b0aa186c6326d0c8 src/main/java/edu/asu/commons/irrigation/conf/ServerConfiguration.java --- a/src/main/java/edu/asu/commons/irrigation/conf/ServerConfiguration.java +++ b/src/main/java/edu/asu/commons/irrigation/conf/ServerConfiguration.java @@ -188,7 +188,7 @@ } public int getChatDuration() { - return getIntProperty("chat-duration", 60); + return getIntProperty("chat-duration", 5); } public String getGameScreenshotInstructions() { diff -r 7bc24ad24c424230a11db6637311436713a0d31d -r a2a5b61d5434c9c3a4dd37a6b0aa186c6326d0c8 src/main/resources/configuration/asu/2011/pretest/irrigation.xml --- a/src/main/resources/configuration/asu/2011/pretest/irrigation.xml +++ b/src/main/resources/configuration/asu/2011/pretest/irrigation.xml @@ -397,11 +397,15 @@ </table><h2>Earnings</h2><hr> - <p>You are in position {clientData.priorityString} and received + <p> + You are in position {clientData.priorityString} and received {clientData.totalDollarsEarnedThisRound} this past round. Your - <b>total income</b> is <b>{clientData.grandTotalIncome}</b>, including the - {showUpPayment} show-up bonus and {clientData.quizEarnings} for - answering {clientData.correctQuizAnswers} quiz questions correctly.</p> + <b>total income</b> is <b>{clientData.grandTotalIncome}</b>, including + the {showUpPayment} show-up bonus + {if (clientData.quizEarnings)} + and {clientData.quizEarnings} for answering {clientData.correctQuizAnswers} quiz questions correctly + {endif} + </p> {if (showExitInstructions)} <h2>Exit Survey</h2><hr> @@ -446,10 +450,10 @@ <tr><th></th></th><th>Infrastructure Efficiency</th><th>Water Delivery Capacity</th><th>Water Availability</th></tr> -<tr> +<tr align='center'><td>Before Investment</td><td>{groupDataModel.infrastructureEfficiencyBeforeInvestment}%</td><td>{groupDataModel.irrigationCapacityBeforeInvestment} cubic feet per second</td><td>{groupDataModel.actualWaterDeliveryCapacity} cubic feet per second</td></tr> -<tr> +<tr align='center'><td>After Investment</td><td>{groupDataModel.infrastructureEfficiency}%</td><td>{groupDataModel.irrigationCapacity} cubic feet per second</td><td>{groupDataModel.actualWaterDeliveryCapacity} cubic feet per second</td></tr></table> Repository URL: https://bitbucket.org/virtualcommons/irrigation/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |