Merge branch 'racecommittee_app' into racecommittee_regattaoverview

This commit is contained in:
Armin Zamani committed 2013-05-24 23:31:46 +02:00
commit b29027fd75
16 files changed
+304 -59

No files matched your search

@@ -12,4 +12,6 @@ public interface PolarSheetsData extends Serializable {
Integer[] getDataCountPerAngleForWindspeed(int beaufort);
Integer[] getStepping();
}
@@ -13,17 +13,20 @@ public class PolarSheetsDataImpl implements PolarSheetsData {
private boolean complete;
private int dataCount;
private Integer[] stepping;
private Map<Integer,Integer[]> dataCountPerAngleForWindspeed;
//For GWT Serialization
PolarSheetsDataImpl() {};
public PolarSheetsDataImpl(Number[][] averagedPolarDataByWindSpeed, boolean complete, int dataCount, Map<Integer,Integer[]> dataCountPerAngleForWindspeed) {
public PolarSheetsDataImpl(Number[][] averagedPolarDataByWindSpeed, boolean complete, int dataCount, Map<Integer,Integer[]> dataCountPerAngleForWindspeed, Integer[] stepping) {
this.averagedPolarDataByWindSpeed = averagedPolarDataByWindSpeed;
this.complete = complete;
this.dataCount = dataCount;
this.dataCountPerAngleForWindspeed = dataCountPerAngleForWindspeed;
this.stepping = stepping;
}
@Override
@@ -46,5 +49,10 @@ public class PolarSheetsDataImpl implements PolarSheetsData {
public Integer[] getDataCountPerAngleForWindspeed(int beaufort) {
return dataCountPerAngleForWindspeed.get(beaufort);
}
@Override
public Integer[] getStepping() {
return stepping;
}
}
@@ -72,9 +72,9 @@ public class PolarSheetGenerationTest {
PolarSheetsData data = resultContainer.getPolarData();
Assert.assertEquals(4, data.getDataCount());
Assert.assertEquals(4.0, data.getAveragedPolarDataByWindSpeed()[1][45]);
Assert.assertEquals(2.0, data.getAveragedPolarDataByWindSpeed()[1][55]);
Assert.assertEquals(6.0, data.getAveragedPolarDataByWindSpeed()[1][30]);
Assert.assertEquals(4.0, data.getAveragedPolarDataByWindSpeed()[0][45]);
Assert.assertEquals(2.0, data.getAveragedPolarDataByWindSpeed()[0][55]);
Assert.assertEquals(6.0, data.getAveragedPolarDataByWindSpeed()[0][30]);
}
@@ -32,6 +32,8 @@ public class PolarSheetGenerationWorker {
private final Executor executor;
private PolarSheetsWindStepping stepping;
/**
* Will prepare the {@link PerRaceAndCompetitorPolarSheetGenerationWorker}s per race & per competitor. This includes
* determining start and end time.
@@ -42,6 +44,8 @@ public class PolarSheetGenerationWorker {
* executes the tasks upon {@link #startPolarSheetGeneration()}
*/
public PolarSheetGenerationWorker(Set<TrackedRace> trackedRaces, Executor executor) {
Integer[] levels = {4,6,8,10,12,14,16,20,25,30};
stepping = new PolarSheetsWindStepping(levels);
polarData = initializePolarDataContainer();
this.executor = executor;
workers = new HashSet<PerRaceAndCompetitorPolarSheetGenerationWorker>();
@@ -107,11 +111,12 @@ public class PolarSheetGenerationWorker {
* product.
*/
public PolarSheetsData getPolarData() {
Number[][] averagedPolarDataByWindSpeed = new Number[13][360];
int levelCount = stepping.getNumberOfLevels();
Number[][] averagedPolarDataByWindSpeed = new Number[levelCount][360];
Integer[] dataCountPerAngle = new Integer[360];
int dataCount = 0;
Map<Integer, Integer[]> dataCountPerAngleForWindspeed = new HashMap<Integer, Integer[]>();
for (int i = 0; i < 13; i++) {
for (int i = 0; i < levelCount; i++) {
dataCountPerAngleForWindspeed.put(i, new Integer[360]);
}
for (int i = 0; i < 360; i++) {
@@ -119,22 +124,22 @@ public class PolarSheetGenerationWorker {
BoatAndWindSpeed[] values = polarData.get(i).toArray(new BoatAndWindSpeed[polarData.get(i).size()]);
dataCount = dataCount + values.length;
dataCountPerAngle[i] = values.length;
double[] sumsPerWindSpeed = new double[13];
int[] dataCountPerWindSpeed = new int[13];
double[] sumsPerWindSpeed = new double[levelCount];
int[] dataCountPerWindSpeed = new int[levelCount];
for (BoatAndWindSpeed singleDataPoint : values) {
if (singleDataPoint != null) {
int windSpeed = (int) singleDataPoint.getWindSpeed().getBeaufort();
//Somehow beaufort sometimes gets bigger than twelve. TODO: Investigation
if (windSpeed > 12) {
windSpeed = 12;
double windSpeed = singleDataPoint.getWindSpeed().getKnots();
int level = stepping.getLevelForValue(windSpeed);
if (level < 0) {
continue;
}
//TODO enable different kinds of metrics for boats speed
sumsPerWindSpeed[windSpeed] = sumsPerWindSpeed[windSpeed] + singleDataPoint.getBoatSpeed().getKnots();
dataCountPerWindSpeed[windSpeed]++;
sumsPerWindSpeed[level] = sumsPerWindSpeed[level] + singleDataPoint.getBoatSpeed().getKnots();
dataCountPerWindSpeed[level]++;
}
}
for (int j = 0; j < 13; j++) {
for (int j = 0; j < levelCount; j++) {
Double average = sumsPerWindSpeed[j] / dataCountPerWindSpeed[j];
if (average.isNaN()) {
average = new Double(0);
@@ -156,7 +161,7 @@ public class PolarSheetGenerationWorker {
}
PolarSheetsData data = new PolarSheetsDataImpl(averagedPolarDataByWindSpeed, complete, dataCount,
dataCountPerAngleForWindspeed);
dataCountPerAngleForWindspeed, stepping.getRawStepping());
return data;
}
@@ -171,4 +176,8 @@ public class PolarSheetGenerationWorker {
return polarData;
}
public PolarSheetsWindStepping getStepping() {
return stepping;
}
}
@@ -0,0 +1,33 @@
package com.sap.sailing.domain.polarsheets;
public class PolarSheetsWindStepping {
private Integer[] levels;
public PolarSheetsWindStepping(Integer[] levels) {
this.levels = levels;
}
public int getNumberOfLevels() {
return levels.length;
}
public int getLevelForValue(double speed) {
for (int i = 0; i < levels.length - 1; i++) {
if (speed < levels[i] || speed < levels[i] + ((levels[i+1] - levels[i]) / 2)) {
return i;
}
}
if (speed < levels[levels.length - 1] + 5) {
return levels.length - 1;
}
//To high over highest level
return -1;
}
public Integer[] getRawStepping() {
return levels;
}
}
@@ -77,9 +77,9 @@ public class PolarSheetGenerationServiceTest {
Assert.assertNotNull(results);
Assert.assertEquals(4, results.getDataCount());
Assert.assertEquals(4.0, results.getAveragedPolarDataByWindSpeed()[1][45]);
Assert.assertEquals(2.0, results.getAveragedPolarDataByWindSpeed()[1][55]);
Assert.assertEquals(6.0, results.getAveragedPolarDataByWindSpeed()[1][30]);
Assert.assertEquals(4.0, results.getAveragedPolarDataByWindSpeed()[0][45]);
Assert.assertEquals(2.0, results.getAveragedPolarDataByWindSpeed()[0][55]);
Assert.assertEquals(6.0, results.getAveragedPolarDataByWindSpeed()[0][30]);
@@ -288,7 +288,7 @@ public interface SailingService extends RemoteService {
PolarSheetsData getPolarSheetsGenerationResults(String id);
PolarSheetsHistogramData getPolarSheetData(String polarSheetId, int angle, int windSpeed);
PolarSheetsHistogramData getPolarSheetData(String polarSheetId, int angle, int windSpeedLevel);
EventDTO getEventById(Serializable id);
@@ -429,7 +429,7 @@ public interface SailingServiceAsync {
void getPolarSheetsGenerationResults(String id, AsyncCallback<PolarSheetsData> asyncCallback);
void getPolarSheetData(String polarSheetId, int angle, int windSpeed, AsyncCallback<PolarSheetsHistogramData> wrapperCallback);
void getPolarSheetData(String polarSheetId, int angle, int windSpeedLevel, AsyncCallback<PolarSheetsHistogramData> wrapperCallback);
void getRegattaOverviewEntriesForEvent(String eventIdAsString, AsyncCallback<List<RegattaOverviewEntryDTO>> asyncCallback);
@@ -25,6 +25,8 @@ public class PolarSheetsChartPanel extends SimplePanel implements RequiresResize
private StringMessages stringMessages;
private Chart chart;
private Map<String, Series[]> seriesMap;
private Map<Series, String> nameForSeries = new HashMap<Series, String>();
public PolarSheetsChartPanel(StringMessages stringMessages) {
this.stringMessages = stringMessages;
@@ -43,21 +45,23 @@ public class PolarSheetsChartPanel extends SimplePanel implements RequiresResize
return polarSheetChart;
}
private void newSeriesArray(String name) {
private void newSeriesArray(String name, int steppingCount) {
if (!seriesMap.containsKey(name)) {
Series[] seriesPerWindSpeed = new Series[13];
Series[] seriesPerWindSpeed = new Series[steppingCount];
seriesMap.put(name, seriesPerWindSpeed);
} else {
// TODO exception handling
}
}
private void createSeriesForWindspeed(String name, int windSpeed) {
private void createSeriesForWindspeed(String name, int windSpeedLevel, int windSpeed) {
Series[] seriesPerWindSpeed = seriesMap.get(name);
Number[] forEachDeg = initializeDataForNewSeries();
seriesPerWindSpeed[windSpeed] = chart.createSeries().setPoints(forEachDeg);
seriesPerWindSpeed[windSpeed].setName(name + "-" + (windSpeed));
chart.addSeries(seriesPerWindSpeed[windSpeed]);
seriesPerWindSpeed[windSpeedLevel] = chart.createSeries().setPoints(forEachDeg);
String actualSeriesName = name + "-" + windSpeed;
seriesPerWindSpeed[windSpeedLevel].setName(actualSeriesName);
nameForSeries.put(seriesPerWindSpeed[windSpeedLevel],actualSeriesName);
chart.addSeries(seriesPerWindSpeed[windSpeedLevel]);
}
private Number[] initializeDataForNewSeries() {
@@ -66,11 +70,12 @@ public class PolarSheetsChartPanel extends SimplePanel implements RequiresResize
}
private void addValuesToSeries(String seriesId, PolarSheetsData result) {
int stepCount = result.getStepping().length;
if (seriesMap.containsKey(seriesId)) {
for (int i = 0; i < 13; i++) {
for (int i = 0; i < stepCount; i++) {
if (hasSufficientDataForWindspeed(result.getDataCountPerAngleForWindspeed(i), result.getDataCount())) {
if (seriesMap.get(seriesId)[i] == null) {
createSeriesForWindspeed(seriesId, i);
createSeriesForWindspeed(seriesId, i, result.getStepping()[i]);
}
Series series = seriesMap.get(seriesId)[i];
series.setPoints(result.getAveragedPolarDataByWindSpeed()[i], false);
@@ -152,7 +157,7 @@ public class PolarSheetsChartPanel extends SimplePanel implements RequiresResize
return;
}
if (!seriesMap.containsKey(id)) {
newSeriesArray(id);
newSeriesArray(id, result.getStepping().length);
}
addValuesToSeries(id, result);
chart.redraw();
@@ -168,4 +173,12 @@ public class PolarSheetsChartPanel extends SimplePanel implements RequiresResize
chart.redraw();
}
public Series[] getSeriesPerWindspeedForName(String name) {
return seriesMap.get(name);
}
public String getNameForSeries(Series series) {
return nameForSeries.get(series);
}
}
@@ -5,17 +5,23 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.moxieapps.gwt.highcharts.client.Point;
import org.moxieapps.gwt.highcharts.client.Series;
import org.moxieapps.gwt.highcharts.client.events.PointMouseOverEvent;
import org.moxieapps.gwt.highcharts.client.events.PointMouseOverEventHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
import com.sap.sailing.domain.common.PolarSheetsData;
@@ -56,6 +62,8 @@ public class PolarSheetsPanel extends FormPanel implements RaceSelectionChangeLi
private Map<String,String> idNameMapping;
private Map<String,String> nameIdMapping;
private ListBox nameListBox;
public PolarSheetsPanel(SailingServiceAsync sailingService, ErrorReporter errorReporter,
StringMessages stringMessages, PolarSheetsEntryPoint polarSheetsEntryPoint) {
this.polarSheetsEntryPoint = polarSheetsEntryPoint;
@@ -81,12 +89,98 @@ public class PolarSheetsPanel extends FormPanel implements RaceSelectionChangeLi
histogramPanel = new PolarSheetsHistogramPanel(stringMessages);
histogramPanel.getElement().setAttribute("align", "top");
rightPanel.add(histogramPanel);
nameListBox = new ListBox();
rightPanel.add(nameListBox);
Button exportButton = new Button("Export");
setExportButtonListener(exportButton);
rightPanel.add(exportButton);
mainPanel.add(splitPanel);
asyncActionsExecutor = new AsyncActionsExecutor();
setEventListenersForPolarSheetChart();
}
private void setExportButtonListener(Button exportButton) {
ClickHandler handler = new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
String name = nameListBox.getItemText(nameListBox.getSelectedIndex());
if (name!=null && !name.isEmpty()) {
StringBuffer exportData = new StringBuffer();
exportData.append(name + "\n");
Series[] seriesPerWindspeed = chartPanel.getSeriesPerWindspeedForName(name);
for (Series series : seriesPerWindspeed) {
if (series == null) {
continue;
}
String nameOfSeries = chartPanel.getNameForSeries(series);
String[] split = nameOfSeries.split("-");
int windSpeed = Integer.parseInt(split[2]);
Point[] points = series.getPoints();
if (windSpeed == 4) {
int[] degs = {0,50,60,110,130,180};
exportData.append("4 " + createStringForDegrees(points, degs) + "\n");
} else if (windSpeed == 6) {
int[] degs = {0,47,60,110,135,180};
exportData.append("6 " + createStringForDegrees(points, degs) + "\n");
} else if (windSpeed == 8) {
int[] degs = {0,43,60,110,135,180};
exportData.append("8 " + createStringForDegrees(points, degs) + "\n");
} else if (windSpeed == 10) {
int[] degs = {0,41,60,110,140,180};
exportData.append("10 " + createStringForDegrees(points, degs) + "\n");
} else if (windSpeed == 12) {
int[] degs = {0,40,60,110,145,180};
exportData.append("12 " + createStringForDegrees(points, degs) + "\n");
} else if (windSpeed == 14) {
int[] degs = {0,39,60,110,155,180};
exportData.append("14 " + createStringForDegrees(points, degs) + "\n");
} else if (windSpeed == 16) {
int[] degs = {0,38,60,110,155,180};
exportData.append("16 " + createStringForDegrees(points, degs) + "\n");
} else if (windSpeed == 20) {
int[] degs = {0,38,60,110,160,180};
exportData.append("20 " + createStringForDegrees(points, degs) + "\n");
} else if (windSpeed == 25) {
int[] degs = {0,39,60,110,168,180};
exportData.append("25 " + createStringForDegrees(points, degs) + "\n");
} else if (windSpeed == 30) {
int[] degs = {0,41,60,110,157,180};
exportData.append("30 " + createStringForDegrees(points, degs) + "\n");
}
}
Window.alert(exportData.toString());
}
}
};
exportButton.addClickHandler(handler);
}
private String createStringForDegrees(Point[] points, int[] degrees) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < degrees.length; i++) {
int deg = degrees[i];
double average;
if (deg > 0 && deg < 180) {
double windRight = points[deg].getY().doubleValue();
double windLeft = points[360 - deg].getY().doubleValue();
average = (windRight + windLeft) / 2;
} else {
average = points[deg].getY().doubleValue();
}
NumberFormat fmt = NumberFormat.getDecimalFormat();
fmt.overrideFractionDigits(2);
buffer.append(deg + " " + fmt.format(average) + " ");
}
return buffer.toString();
}
private void setEventListenersForPolarSheetChart() {
PointMouseOverEventHandler pointMouseOverHandler = new PointMouseOverEventHandler() {
@@ -201,6 +295,7 @@ public class PolarSheetsPanel extends FormPanel implements RaceSelectionChangeLi
index++;
name = boatClassName + "-" + index;
} while (nameIdMapping.containsKey(name));
nameListBox.addItem(name);
idNameMapping.put(result.getId(), name);
nameIdMapping.put(name, result.getId());
}
@@ -130,6 +130,7 @@ import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
import com.sap.sailing.domain.polarsheets.BoatAndWindSpeed;
import com.sap.sailing.domain.polarsheets.PolarSheetGenerationWorker;
import com.sap.sailing.domain.polarsheets.PolarSheetsWindStepping;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogFlagEvent;
import com.sap.sailing.domain.racelog.analyzing.impl.GateLineOpeningTimeFinder;
@@ -2694,6 +2695,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
if (httpServletRequest != null) {
HttpSession session = httpServletRequest.getSession();
session.setAttribute(id, worker.getCompleteData());
session.setAttribute("stepping", worker.getStepping());
}
}
} else {
@@ -2718,11 +2720,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
//TODO exception handling
return null;
}
PolarSheetsWindStepping stepping = (PolarSheetsWindStepping) session.getAttribute("stepping");
List<Double> dataForAngleAndWindSpeed = new ArrayList<Double>();
int windSpeedLevel = stepping.getLevelForValue(windSpeed);
for (BoatAndWindSpeed dataPoint: dataForAngle) {
if (((int) dataPoint.getWindSpeed().getBeaufort()) == windSpeed) {
if ((stepping.getLevelForValue(dataPoint.getWindSpeed().getKnots()) == windSpeedLevel)) {
dataForAngleAndWindSpeed.add(dataPoint.getBoatSpeed().getKnots());
}
}
@@ -18,20 +18,61 @@
<div id='yield_content'>
<div id='mainContent'>
<h1 id='pageHeadline'>Extreme Sailing Series 2013</h1>
<h2>Leaderboards</h2>
<h2>Next Event</h2>
<p>
Act 3 - Qingdao, China
Act 4 - Istanbul, Turkey
</p>
<p>
May 2nd - 5th
June 20th - 23th
</p>
<!--
<p>
Act 5 - Porto, Portugal
</p>
<p>
July 25th - 28th
</p>
<p>
Act 6 - Cardiff, England
</p>
<p>
August 22th - 25th
</p>
<p>
Act 7 - Nice, France
</p>
<p>
October 3th - 6th
</p>
-->
</div>
<div id='navigation'>
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Qingdao%20%28Extreme40%29&displayName=Qingdao&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Qingdao Act Leaderboard
</a>
<a class='navButton overall' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=Extreme%20Sailing%20Series%202013%20Overall&amp;showRaceDetails=false&amp;refreshIntervalMillis=10000&amp;displayName=Overall%20Standings&amp;leaderboardGroupName=Extreme%20Sailing%20Series%202013&amp;root=leaderboardGroupPanel'>
Series Leaderboard
Overall Leaderboard
</a>
<!--<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Rio%20%28Extreme40%29&displayName=Rio&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Rio de Janeiro
</a>
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Nice%20%28Extreme40%29&displayName=Nice&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Nice
</a>
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Cardiff%20%28Extreme40%29&displayName=Cardiff&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Cardiff
</a>
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Porto%20%28Extreme40%29&displayName=Porto&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Porto
</a>-->
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Istanbul%20%28Extreme40%29&displayName=Istanbul&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Istanbul
</a>
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Qingdao%20%28Extreme40%29&displayName=Qingdao&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Qingdao
</a>
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Singapore%20%28Extreme40%29&displayName=Singapore&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Singapore
</a>
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Muscat%20%28Extreme40%29&displayName=Muscat&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Muscat
</a>
</div>
</div>
+40 -20
View File
@@ -29,6 +29,46 @@
<div class='innerContent'>
<h2 class='articleSubheadline'>2013</h2>
<div class='timeBar'>
<!--<div class='raceSection'>
<h5 class='date'>
July 25 - 28
</h5>
<div class='raceTimepoint'></div>
<a href='http://ess40-2013.sapsailing.com' target='_blank'>
<ul class='racePanel'>
<li class='raceName'>
Extreme Sailing Series 2013
</li>
<li class='raceLocation'>
Porto, Portugal
</li>
</ul>
</a>
<div class='raceDescription'>
<p>Extreme Sailing Series 2013</p>
<a href='http://www.extremesailingseries.com' target='_blank'>Official website</a>
</div>
</div>-->
<div class='raceSection'>
<h5 class='date'>
June 20 - 23
</h5>
<div class='raceTimepoint'></div>
<a href='http://ess40-2013.sapsailing.com' target='_blank'>
<ul class='racePanel'>
<li class='raceName'>
Extreme Sailing Series 2013
</li>
<li class='raceLocation'>
Istanbul, Turkey
</li>
</ul>
</a>
<div class='raceDescription'>
<p>Extreme Sailing Series 2013</p>
<a href='http://www.extremesailingseries.com' target='_blank'>Official website</a>
</div>
</div>
<div class='raceSection'>
<h5 class='date'>
May 1 - 5
@@ -48,26 +88,6 @@
<p>Star IDM 2013</p>
<a href='http://www.starclass.de/termine-detail/events/int-deutsche-meisterschaft-2013.html' target='_blank'>Official website</a>
</div>
</div>
<div class='raceSection'>
<h5 class='date'>
May 2 - 5
</h5>
<div class='raceTimepoint'></div>
<a href='http://ess40-2013.sapsailing.com' target='_blank'>
<ul class='racePanel'>
<li class='raceName'>
Extreme Sailing Series 2013
</li>
<li class='raceLocation'>
Qingdao, China
</li>
</ul>
</a>
<div class='raceDescription'>
<p>Extreme Sailing Series 2013</p>
<a href='http://www.extremesailingseries.com' target='_blank'>Official website</a>
</div>
</div>
<div class='raceSection'>
<h5 class='date'>