diff --git a/configuration/releaseAndroidApps.sh b/configuration/releaseAndroidApps.sh index c97824ede70..68430deff26 100755 --- a/configuration/releaseAndroidApps.sh +++ b/configuration/releaseAndroidApps.sh @@ -85,7 +85,9 @@ git checkout $ANDROID_RELEASE_BRANCH git merge -m "Merging $GIT_REMOTE/$ANDROID_RELEASE_BRANCH" $GIT_REMOTE/$ANDROID_RELEASE_BRANCH git fetch $GIT_REMOTE $RELEASE_BRANCH:$RELEASE_BRANCH git merge -m "Merging $RELEASE_BRANCH into $ANDROID_RELEASE_BRANCH, probably incorporating version setting to -SNAPSHOT" $GIT_REMOTE/$RELEASE_BRANCH -git push $GIT_REMOTE $ANDROID_RELEASE_BRANCH:$ANDROID_RELEASE_BRANCH +if [ "$PERFORM_GIT_OPERATIONS" = "1" ]; then + git push $GIT_REMOTE $ANDROID_RELEASE_BRANCH:$ANDROID_RELEASE_BRANCH +fi # Patch the AndroidManifest.xml files to upgrade the android:versionCode sequential counter relevant for the PlayStore # and the android:versionName which is what the user sees and which we expect to follow a major.minor version scheme, diff --git a/doc/SAPSailingAnalytics_Administrator_Training.pptx b/doc/SAPSailingAnalytics_Administrator_Training.pptx index 7dd67d8a5f3..ddae3ea0b3d 100644 Binary files a/doc/SAPSailingAnalytics_Administrator_Training.pptx and b/doc/SAPSailingAnalytics_Administrator_Training.pptx differ diff --git a/home.md b/home.md index 2ff9a805a82..572b28c7185 100644 --- a/home.md +++ b/home.md @@ -1,148 +1,149 @@ -# Welcome to the SAP Sailing Wiki - -This is the Wiki where useful information regarding this project can be found. - -### The Pitch - -Like businesses, sailors need the latest information to make strategic decisions - but they need it even faster. One wrong tack, a false estimation of the current, or the slightest wind shift can cost the skipper the entire race. As premium sponsor of the Kieler Woche 2011, and co-sponsor of Sailing Team Germany (STG), SAP is showing how innovative IT solutions providing real time data analysis can give teams the competitive edge. - -SAP is at the center of today’s technology revolution, developing innovations that not only help businesses run like never before, but also improve the lives of people everywhere. As market leader in enterprise application software, SAP SE (NYSE: SAP) helps companies of all sizes and industries run better. From back office to boardroom, warehouse to storefront, desktop to mobile device – SAP empowers people and organizations to work together more efficiently and use business insight more effectively to stay ahead of the competition. SAP applications and services enable more than 258,000 customers to operate profitably, adapt continuously, and grow sustainably. - -# Table of Contents - -## Information - -### General - -* [[Information about this Wiki and HowTo|wiki/info/general/wiki]] -* [[General Project Information|wiki/info/general/general-information]] -* [[Inventory|wiki/info/general/inventar-liste]] - -### Landscape and Development - -* [[Architecture and Infrastructure|wiki/info/landscape/architecture-and-infrastructure]] - * [[Runtime Environment|wiki/info/landscape/runtime-environment]] - * [[Basic architectual principles|wiki/info/landscape/basic-architectural-principles]] - * [[User Management|wiki/info/landscape/usermanagement]] - * [[Development Environment|wiki/info/landscape/development-environment]] - * [[Production Environment|wiki/info/landscape/production-environment]] - * [[Typical Development Scenarios|wiki/info/landscape/typical-development-scenarios]] -* [[RaceLog Tracking Server Architecture|wiki/info/landscape/server]] - * Environment Overview [[PDF|wiki/info/mobile/event-tracking/architecture.pdf]] | [[SVG|wiki/info/mobile/event-tracking/architecture.svg]] -* Amazon - * [[Amazon EC2|wiki/info/landscape/amazon-ec2]] - * [[EC2 Backup Strategy|wiki/info/landscape/amazon-ec2-backup-strategy]] - * [[Creating an EC2 image from scratch|wiki/info/landscape/creating-ec2-image-from-scratch]] - * [[EC2 mail relaying|wiki/info/landscape/mail-relaying]] -* [[Building and Deploying|wiki/info/landscape/building-and-deploying]] -* [[Data Mining Architecture|wiki/info/landscape/data-mining-architecture]] -* [[Typical Data Mining Scenarios|wiki/info/landscape/typical-data-mining-scenarios]] -* [[Create clickable UI prototypes with Axure|wiki/info/landscape/ui-clickable-prototypes]] -* [[Webdesign|wiki/info/landscape/webdesign]] - -### Mobile - -* [[Mobile Development|wiki/info/mobile/mobile-development]] -* Tracking App - * [[Tracking App Specification|wiki/info/mobile/app-spec/app-spec]] - * [[Event Tracking|wiki/info/mobile/event-tracking/event-tracking]] - * [[Steps for setting up Smartphone Tracking|wiki/info/mobile/smartphone-tracking-steps]] - * [[Tracking App Prototype Architecture|wiki/info/mobile/app]] -* Racecommittee App - * [[Racecommittee App|wiki/info/mobile/racecommittee-app]] - * [[Environment|wiki/info/mobile/racecommittee-app-environment]] - * [[Administrator|wiki/info/mobile/racecommittee-app-administrator]] - * [[User|wiki/info/mobile/racecommittee-app-user]] -* [[Android and Release Build|wiki/info/mobile/android-and-release-build]] -* [[Energy consumption of mobile apps|wiki/info/mobile/energy-consumption]] -* [[Data consumption of mobile apps|wiki/info/mobile/data-consumption]] -* [[Mobile Sailing Analytics|wiki/info/mobile/mobilesailinganalytics]] -* [[Push Notifications|wiki/info/mobile/push-notifications]] - -### API - -* [[Web Services API|wiki/info/api/sailing-webservices]] -* [[API v1|wiki/info/api/api-v1]] -* [[Tracking App API|wiki/info/api/tracking-app-api]] -* [[Training API v1 draft|wiki/info/api/training-api-v1-draft]] - -### Security - * [[Fortify Tests|wiki/info/security/fortify]] - * [[SSL / HTTPS Support|wiki/info/security/ssl-support]] - -### Miscellaneous - -* [[Big Data - Numbers|wiki/info/misc/big-data-numbers]] -* [[Data Quality|wiki/info/misc/data-quality]] -* [[Sailing Domain Algorithms|wiki/info/misc/sailing-domain-algorithms]] -* [[Google Analytics (Web Page Tracking)|wiki/info/misc/ganalytics]] -* [[S3 Development Sample|wiki/info/misc/s3-sample]] - -* [[FAQ for League Operators|wiki/info/misc/league-operators-faq]] -* [[Prionet related information|wiki/info/misc/prionet-related-information]] -* [[TracTrac Workshop 2013|wiki/info/misc/tractracworkshop2013]] - -## HowTo - -* [[Onboarding|wiki/howto/onboarding]] - - -### Development - -* [[Create boat graphics for the 2D race viewer|wiki/howto/development/boatgraphicssvg]] -* [[Continuous Integration with Hudson/Jenkins|wiki/howto/development/ci]] -* [[Dispatch|wiki/howto/development/dispatch]] -* [[Working with GWT UI Binder|wiki/howto/development/gwt-ui-binder]] -* [[Java De(Serialization) and Circular Dependencies|wiki/howto/development/java-de-serialization-and-circular-dependencies]] -* [[JMX Support|wiki/howto/development/jmx]] -* [[Working with GWT Locally|wiki/howto/development/local-gwt]] -* [[Log File Analysis|wiki/howto/development/log-file-analysis]] -* [[UI Tests with Selenium|wiki/howto/development/selenium-ui-tests]] -* [[Profiling|wiki/howto/development/profiling]] -* [[Working with GWT Super Dev Mode|wiki/howto/development/super-dev-mode]] - -### For Event Managers - -* [[Set up local network with replication server|wiki/howto/eventmanagers/event-network-with-replica]] -* [[Operating Igtimi WindBots|wiki/howto/eventmanagers/windbot-operations]] -* [[Linking Race Videos|wiki/howto/eventmanagers/linking-race-videos]] -* [[Import official results|wiki/howto/eventmanagers/results-import]] - -### Setup - -* [[Configure Races on Server|wiki/howto/setup/configure-races-on-server]] -* [[Setting up internal Jenkins on SAP Monsoon|wiki/howto/setup/setting-up-jenkins-on-sap-monsoon]] - -### Miscellaneous - -* [[Cook Book|wiki/howto/misc/cook-book]] -* [[Polars|wiki/howto/misc/polars]] -* [[Server Replication|wiki/howto/misc/server-replication]] -* [[TracTrac|wiki/howto/misc/tractrac-lifecycle]] -* [[UI Tests|wiki/howto/misc/ui-tests-tutorial]] -* [[Uploading Media Content|wiki/howto/misc/uploading-media-content]] -* [[Monitoring Apache and RabbitMQ|wiki/misc/monitoring-apache-and-rabbitmq]] - -## Projects -* [[Analytics on a stick|wiki/projects/analytics-on-a-stick]] - -## Events and Planning -* [[Project Planning (bigger development)|wiki/events/planning]] -* [[General Event Planning|wiki/events/general-event-planning]] -* [[Information about Extreme Sailing Series|wiki/events/extreme-sailing-series]] -* [[Travemünder Woche 2014 event page|wiki/events/tw2014]] -* [[505 worlds Kiel 2014 event page|wiki/events/505-worlds-kiel-2014]] -* [[Kieler Woche event page|wiki/events/kieler-woche-2015]] -* [[Charleston Race Week 2016|wiki/events/Charleston-Race-Week-2016]] -* [[Sailing Leagues 2016|wiki/events/sailing-Leagues-2016]] - -## Planning -* [[Overview|https://wiki.sapsailing.com/pages/wiki/planning/]] - -## Internal services (not related to wiki but useful) - -* [Bugzilla Issue Tracking System](http://bugzilla.sapsailing.com/bugzilla/) -* [GIT Repository (SAP)](ssh://git.wdf.sap.corp:29418/SAPSail/sapsailingcapture.git) -* [Maven Repository Browser](http://maven.sapsailing.com/maven/) (see [[how to setup repository for Android builds|wiki/info/mobile/racecommittee-app-environment]]) -* [Main Sailing Website](http://www.sapsailing.com) -* [Visitor Statistics](http://analysis.sapsailing.com/) +# Welcome to the SAP Sailing Wiki + +This is the Wiki where useful information regarding this project can be found. + +### The Pitch + +Like businesses, sailors need the latest information to make strategic decisions - but they need it even faster. One wrong tack, a false estimation of the current, or the slightest wind shift can cost the skipper the entire race. As premium sponsor of the Kieler Woche 2011, and co-sponsor of Sailing Team Germany (STG), SAP is showing how innovative IT solutions providing real time data analysis can give teams the competitive edge. + +SAP is at the center of today’s technology revolution, developing innovations that not only help businesses run like never before, but also improve the lives of people everywhere. As market leader in enterprise application software, SAP SE (NYSE: SAP) helps companies of all sizes and industries run better. From back office to boardroom, warehouse to storefront, desktop to mobile device – SAP empowers people and organizations to work together more efficiently and use business insight more effectively to stay ahead of the competition. SAP applications and services enable more than 258,000 customers to operate profitably, adapt continuously, and grow sustainably. + +# Table of Contents + +## Information + +### General + +* [[Information about this Wiki and HowTo|wiki/info/general/wiki]] +* [[General Project Information|wiki/info/general/general-information]] +* [[Inventory|wiki/info/general/inventar-liste]] + +### Landscape and Development + +* [[Architecture and Infrastructure|wiki/info/landscape/architecture-and-infrastructure]] + * [[Runtime Environment|wiki/info/landscape/runtime-environment]] + * [[Basic architectual principles|wiki/info/landscape/basic-architectural-principles]] + * [[User Management|wiki/info/landscape/usermanagement]] + * [[Development Environment|wiki/info/landscape/development-environment]] + * [[Production Environment|wiki/info/landscape/production-environment]] + * [[Typical Development Scenarios|wiki/info/landscape/typical-development-scenarios]] +* [[RaceLog Tracking Server Architecture|wiki/info/landscape/server]] + * Environment Overview [[PDF|wiki/info/mobile/event-tracking/architecture.pdf]] | [[SVG|wiki/info/mobile/event-tracking/architecture.svg]] +* Amazon + * [[Amazon EC2|wiki/info/landscape/amazon-ec2]] + * [[EC2 Backup Strategy|wiki/info/landscape/amazon-ec2-backup-strategy]] + * [[Creating an EC2 image from scratch|wiki/info/landscape/creating-ec2-image-from-scratch]] + * [[EC2 mail relaying|wiki/info/landscape/mail-relaying]] +* [[Building and Deploying|wiki/info/landscape/building-and-deploying]] +* [[Data Mining Architecture|wiki/info/landscape/data-mining-architecture]] +* [[Typical Data Mining Scenarios|wiki/info/landscape/typical-data-mining-scenarios]] +* [[Create clickable UI prototypes with Axure|wiki/info/landscape/ui-clickable-prototypes]] +* [[Webdesign|wiki/info/landscape/webdesign]] + +### Mobile + +* [[Mobile Development|wiki/info/mobile/mobile-development]] +* Tracking App + * [[Tracking App Specification|wiki/info/mobile/app-spec/app-spec]] + * [[Event Tracking|wiki/info/mobile/event-tracking/event-tracking]] + * [[Steps for setting up Smartphone Tracking|wiki/info/mobile/smartphone-tracking-steps]] + * [[Tracking App Prototype Architecture|wiki/info/mobile/app]] +* Racecommittee App + * [[Racecommittee App|wiki/info/mobile/racecommittee-app]] + * [[Environment|wiki/info/mobile/racecommittee-app-environment]] + * [[Administrator|wiki/info/mobile/racecommittee-app-administrator]] + * [[User|wiki/info/mobile/racecommittee-app-user]] +* [[Android and Release Build|wiki/info/mobile/android-and-release-build]] +* [[Energy consumption of mobile apps|wiki/info/mobile/energy-consumption]] +* [[Data consumption of mobile apps|wiki/info/mobile/data-consumption]] +* [[Mobile Sailing Analytics|wiki/info/mobile/mobilesailinganalytics]] +* [[Push Notifications|wiki/info/mobile/push-notifications]] +* [[NMEA|wiki/info/mobile/nmea]] + +### API + +* [[Web Services API|wiki/info/api/sailing-webservices]] +* [[API v1|wiki/info/api/api-v1]] +* [[Tracking App API|wiki/info/api/tracking-app-api]] +* [[Training API v1 draft|wiki/info/api/training-api-v1-draft]] + +### Security + * [[Fortify Tests|wiki/info/security/fortify]] + * [[SSL / HTTPS Support|wiki/info/security/ssl-support]] + +### Miscellaneous + +* [[Big Data - Numbers|wiki/info/misc/big-data-numbers]] +* [[Data Quality|wiki/info/misc/data-quality]] +* [[Sailing Domain Algorithms|wiki/info/misc/sailing-domain-algorithms]] +* [[Google Analytics (Web Page Tracking)|wiki/info/misc/ganalytics]] +* [[S3 Development Sample|wiki/info/misc/s3-sample]] + +* [[FAQ for League Operators|wiki/info/misc/league-operators-faq]] +* [[Prionet related information|wiki/info/misc/prionet-related-information]] +* [[TracTrac Workshop 2013|wiki/info/misc/tractracworkshop2013]] + +## HowTo + +* [[Onboarding|wiki/howto/onboarding]] + + +### Development + +* [[Create boat graphics for the 2D race viewer|wiki/howto/development/boatgraphicssvg]] +* [[Continuous Integration with Hudson/Jenkins|wiki/howto/development/ci]] +* [[Dispatch|wiki/howto/development/dispatch]] +* [[Working with GWT UI Binder|wiki/howto/development/gwt-ui-binder]] +* [[Java De(Serialization) and Circular Dependencies|wiki/howto/development/java-de-serialization-and-circular-dependencies]] +* [[JMX Support|wiki/howto/development/jmx]] +* [[Working with GWT Locally|wiki/howto/development/local-gwt]] +* [[Log File Analysis|wiki/howto/development/log-file-analysis]] +* [[UI Tests with Selenium|wiki/howto/development/selenium-ui-tests]] +* [[Profiling|wiki/howto/development/profiling]] +* [[Working with GWT Super Dev Mode|wiki/howto/development/super-dev-mode]] + +### For Event Managers + +* [[Set up local network with replication server|wiki/howto/eventmanagers/event-network-with-replica]] +* [[Operating Igtimi WindBots|wiki/howto/eventmanagers/windbot-operations]] +* [[Linking Race Videos|wiki/howto/eventmanagers/linking-race-videos]] +* [[Import official results|wiki/howto/eventmanagers/results-import]] + +### Setup + +* [[Configure Races on Server|wiki/howto/setup/configure-races-on-server]] +* [[Setting up internal Jenkins on SAP Monsoon|wiki/howto/setup/setting-up-jenkins-on-sap-monsoon]] + +### Miscellaneous + +* [[Cook Book|wiki/howto/misc/cook-book]] +* [[Polars|wiki/howto/misc/polars]] +* [[Server Replication|wiki/howto/misc/server-replication]] +* [[TracTrac|wiki/howto/misc/tractrac-lifecycle]] +* [[UI Tests|wiki/howto/misc/ui-tests-tutorial]] +* [[Uploading Media Content|wiki/howto/misc/uploading-media-content]] +* [[Monitoring Apache and RabbitMQ|wiki/misc/monitoring-apache-and-rabbitmq]] + +## Projects +* [[Analytics on a stick|wiki/projects/analytics-on-a-stick]] + +## Events and Planning +* [[Project Planning (bigger development)|wiki/events/planning]] +* [[General Event Planning|wiki/events/general-event-planning]] +* [[Information about Extreme Sailing Series|wiki/events/extreme-sailing-series]] +* [[Travemünder Woche 2014 event page|wiki/events/tw2014]] +* [[505 worlds Kiel 2014 event page|wiki/events/505-worlds-kiel-2014]] +* [[Kieler Woche event page|wiki/events/kieler-woche-2015]] +* [[Charleston Race Week 2016|wiki/events/Charleston-Race-Week-2016]] +* [[Sailing Leagues 2016|wiki/events/sailing-Leagues-2016]] + +## Planning +* [[Overview|https://wiki.sapsailing.com/pages/wiki/planning/]] + +## Internal services (not related to wiki but useful) + +* [Bugzilla Issue Tracking System](http://bugzilla.sapsailing.com/bugzilla/) +* [GIT Repository (SAP)](ssh://git.wdf.sap.corp:29418/SAPSail/sapsailingcapture.git) +* [Maven Repository Browser](http://maven.sapsailing.com/maven/) (see [[how to setup repository for Android builds|wiki/info/mobile/racecommittee-app-environment]]) +* [Main Sailing Website](http://www.sapsailing.com) +* [Visitor Statistics](http://analysis.sapsailing.com/) diff --git a/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT.launch b/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT.launch index e6b9e6eed4d..324e2b3954d 100644 --- a/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT.launch +++ b/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT.launch @@ -3,7 +3,7 @@ - + @@ -38,7 +38,7 @@ - + diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties index 270fcb64c37..2cf4ae6cf36 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -97,7 +97,7 @@ WindSourceName=Wind Source Name windFrom=True Wind Direction (TWD) windSpeedKnots=True Wind Speed (kts) speedInKnots=Speed (kts) -bearing=Direction (T) +bearing=Direction (°T) WindTrack=Wind Track timeSpentFoiling=Time spent foiling yaw=Yaw diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties index bc7c0e6f9f1..38878b0106c 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties @@ -1,11 +1,11 @@ Competitor=Teilnehmer -DistanceTraveled=zurckgelegte Distanz +DistanceTraveled=zurückgelegte Distanz Boat=Boot Team=Team Name=Name SearchTag=Such-Tag -Nationality=Nationalitts -Acronym=Abkrzung +Nationality=Nationalitäts +Acronym=Abkürzung SailID=Segelnummer LegNumber=Nummer des Schenkels LegType=Art des Schenkels @@ -26,7 +26,7 @@ WindFixSailingDomainRetrieverChain=Windmessungen MarkPassingSailingDomainRetrieverChain=Tonnenrundungen RaceResultSailingDomainRetrieverChain=Rennergebnisse RaceOfCompetitorSailingDomainRetrieverChain=Rennen eines Teilnehmers -ManeuverSailingDomainRetrieverChain=Manver +ManeuverSailingDomainRetrieverChain=Manöver LeaderboardGroup=Ranglisten Gruppe Leaderboard=Rangliste Leg=Schenkel @@ -36,19 +36,19 @@ GpsFix=GPS-Fix BravoFix=Bravo-Fix BravoFixTrack=Bravo-Messreihe WindFix=Windmessung -Maneuver=Manver +Maneuver=Manöver Speed=Geschwindigkeit SpeedTenSecondsBefore=Geschwindigkeit 10s vorher -WindStrengthInBeaufort=Windstrke in Beaufort +WindStrengthInBeaufort=Windstärke in Beaufort Bft0=Windstille Bft1=leiser Zug Bft2=leichte Brise Bft3=schwacher Wind -Bft4=miger Wind +Bft4=mäßiger Wind Bft5=frischer Wind Bft6=starker Wind Bft7=steifer Wind -Bft8=strmischer Wind +Bft8=stürmischer Wind Bft9=Sturm Bft10=schwerer Sturm Bft11=orkanartiger Sturm @@ -59,53 +59,53 @@ RelativeScoreInRaceInPercent=Relative Wertung im Rennen in % AbsoluteRank=Absolute Platzierung WindSpeedInBeaufort=Windgeschwindigkeit in Bft. DistanceAtStart=Distanz zur Startlinie zum Startzeitpunkt -SpeedWhenStarting=Geschwindigkeit beim berqueren der Startlinie +SpeedWhenStarting=Geschwindigkeit beim Überqueren der Startlinie SpeedTenSecondsBeforeStart=Geschwindigkeit 10s vor dem Startzeitpunkt RankAtFirstMark=Position beim ersten Wegpunkt -NumberOfManeuvers=Anzahl der Manver +NumberOfManeuvers=Anzahl der Manöver NumberOfTacks=Anzahl der Wenden NumberOfJibes=Anzahl der Halsen NumberOfPenaltyCircles=Anzahl der Straf-Kreise RankGainsOrLosses=Positions-Verluste oder -Gewinne -DistanceToStarboardSideAtStart=Distanz zur Steuerbordseite (% der Lnge) +DistanceToStarboardSideAtStart=Distanz zur Steuerbordseite (% der Länge) NumberOfPodiumFinish=Azahl der Podium-Siege NumberOfWins=Anzahl der Siege RankGainsOrLossesBetweenFirstMarkAndFinish=Positions-Verluste oder -Gewinne (1ter Wegpunkt -> Ziel) IsTracked=Ist getracked NumberOfCompetitorFixes=Anzahl der Teilnehmer-Fixes NumberOfMarkFixes=Anzahl der Tonnen-Fixes -ManeuverType=Art des Manvers +ManeuverType=Art des Manövers Tack=Bug -SpeedBefore=Geschwindigkeit bevor dem Manver -SpeedAfter=Geschwindigkeit nach dem Manver -DirectionChange=Richtungsnderung in Grad -AbsoluteDirectionChange=Absolute Richtungsnderung in Grad (positiv) +SpeedBefore=Geschwindigkeit bevor dem Manöver +SpeedAfter=Geschwindigkeit nach dem Manöver +DirectionChange=Richtungsänderung in Grad +AbsoluteDirectionChange=Absolute Richtungsänderung in Grad (positiv) ToSide=In Richtung (Backbord / Steuerbord) -ManeuverLoss=Manververlust +ManeuverLoss=Manöververlust Waypoint=Wegpunkt PassingSide=Passierende Seite TackAtStart=Startbug SpeedTenSecondsAfterStart=Geschwindigkeit 10s nach dem Startzeitpunkt RankThirtySecondsAfterStart=Absolute Platzierung 30s nach dem Startzeitpunkt -WindwardDistanceToAdvantageousEndOfLine=Windwrtige Distanz zum Bevorteilten Ende der Startlinie -RankAfterHalfOfTheFirstLeg=Platzierung nach der Hlfte des ersten Schenkels +WindwardDistanceToAdvantageousEndOfLine=Windwärtige Distanz zum Bevorteilten Ende der Startlinie +RankAfterHalfOfTheFirstLeg=Platzierung nach der Hälfte des ersten Schenkels AdvantageousEndOfLine=Bevorteiltes Ende der Startlinie -TimeSpentInSeconds=Bentigte Zeit in Sekunden +TimeSpentInSeconds=Benötigte Zeit in Sekunden MedalRace=Medaillenrennen WindSourceType=Art der Windmessung WindSourceName=Name der Windmessreihe windFrom=Wind aus Richtung (TWD) windSpeedKnots=Wahre Windgeschwindigkeit (kn) speedInKnots=Fahrt (kn) -bearing=Richtung () +bearing=Richtung (°) WindTrack=Windmessreihe timeSpentFoiling=Zeit auf Foils yaw=Gierung pitch=Neigung -heel=Krngung -rideHeight=Foiling-Hhe -rideHeightPort=Foiling-Hhe Backbord-Rumpf -rideHeightStarboard=Foiling-Hhe Steuerbord-Rumpf +heel=Krängung +rideHeight=Foiling-Höhe +rideHeightPort=Foiling-Höhe Backbord-Rumpf +rideHeightStarboard=Foiling-Höhe Steuerbord-Rumpf IsFoiling=Foilt FoilingDuration=Foilingdauer FoilingDistance=Gefoilte Distanz @@ -113,8 +113,8 @@ TakeoffSpeedInKnotsInKnots=Abhebegeschwindigkeit in Knoten LandingSpeedInKnots=Landegeschwindigkeit in Knoten AbsoluteTrueWindAngleAtTakeoff=Absoluter Winkel zum wahren Wind (TWA) beim Abheben AbsoluteTrueWindAngleAtLanding=Absoluter Winkel zum wahren Wind (TWA) beim Landen -WindStrengthInBeaufortAtTakeoff=Windstrke beim Abheben in Beaufort -WindStrengthInBeaufortAtLanding=Windstrke beim Landen in Beaufort +WindStrengthInBeaufortAtTakeoff=Windstärke beim Abheben in Beaufort +WindStrengthInBeaufortAtLanding=Windstärke beim Landen in Beaufort WindAtTakeoff=Wind beim Abheben WindAtLanding=Wind beim Landen StartsOnLegType=Bahnschnenkeltyp beim Abheben diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_fr.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_fr.properties index 88bc7ee0d9a..6f159b878f5 100755 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_fr.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_fr.properties @@ -97,7 +97,7 @@ WindSourceName=Nom de la source du vent windFrom=Direction réelle du vent (TWD) windSpeedKnots=Vitesse réelle du vent (en nds) speedInKnots=Vitesse (nds) -bearing=Direction (�T) +bearing=Direction (°T) WindTrack=Enregistrement vent timeSpentFoiling=Temps passé en planing yaw=Dévier diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/Activator.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/Activator.java index 277a985a470..a4b07bf9900 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/Activator.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/Activator.java @@ -1,5 +1,6 @@ package com.sap.sailing.datamining; +import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.HashSet; import java.util.Map; @@ -61,7 +62,8 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries private boolean dataSourceProvidersHaveBeenInitialized; public Activator() { - sailingServerStringMessages = new ResourceBundleStringMessagesImpl(STRING_MESSAGES_BASE_NAME, getClassLoader()); + sailingServerStringMessages = new ResourceBundleStringMessagesImpl(STRING_MESSAGES_BASE_NAME, getClassLoader(), + StandardCharsets.UTF_8.name()); dataRetrieverChainDefinitions = new SailingDataRetrievalChainDefinitions(); predefinedQueries = new SailingPredefinedQueries(); } diff --git a/java/com.sap.sailing.domain.common/.settings/org.eclipse.core.resources.prefs b/java/com.sap.sailing.domain.common/.settings/org.eclipse.core.resources.prefs index c111da40d73..10a03d63ab8 100755 --- a/java/com.sap.sailing.domain.common/.settings/org.eclipse.core.resources.prefs +++ b/java/com.sap.sailing.domain.common/.settings/org.eclipse.core.resources.prefs @@ -2,4 +2,5 @@ eclipse.preferences.version=1 encoding//src/com/sap/sailing/domain/common/AbstractBearing.java=UTF-8 encoding//src/com/sap/sailing/domain/common/confidence/impl/ConfidenceBasedAveragerImpl.java=utf-8 encoding//src/com/sap/sailing/domain/common/impl/AbstractSpeedWithAbstractBearingImpl.java=UTF-8 -encoding//src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java=UTF-8 +encoding//src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactGPSFixMovingImpl.java=UTF-8 +encoding//src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixMovingImpl.java=UTF-8 diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/MasterDataImportObjectCreationCount.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/MasterDataImportObjectCreationCount.java index d44d06e960a..0b63d3fc7fd 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/MasterDataImportObjectCreationCount.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/MasterDataImportObjectCreationCount.java @@ -3,16 +3,18 @@ package com.sap.sailing.domain.common; import java.io.Serializable; import java.util.Set; -public interface MasterDataImportObjectCreationCount extends Serializable{ +public interface MasterDataImportObjectCreationCount extends Serializable { + int getLeaderboardCount(); - public abstract int getLeaderboardCount(); + int getLeaderboardGroupCount(); - public abstract int getLeaderboardGroupCount(); + int getEventCount(); - public abstract int getEventCount(); + int getRegattaCount(); - public abstract int getRegattaCount(); + int getMediaTrackCount(); - public abstract Set getOverwrittenRegattaNames(); + Set getOverwrittenRegattaNames(); + void addOneMediaTrack(); } \ No newline at end of file diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ScoringSchemeType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ScoringSchemeType.java index fd57cced22b..d9cc8610b5b 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ScoringSchemeType.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ScoringSchemeType.java @@ -4,6 +4,6 @@ public enum ScoringSchemeType { // make sure to also add new ones to ScoringSchemeTypeFormatter LOW_POINT, HIGH_POINT, HIGH_POINT_ESS_OVERALL,HIGH_POINT_ESS_OVERALL_12, HIGH_POINT_LAST_BREAKS_TIE, HIGH_POINT_FIRST_GETS_TEN, HIGH_POINT_FIRST_GETS_ONE, LOW_POINT_WINNER_GETS_ZERO, HIGH_POINT_WINNER_GETS_SIX, HIGH_POINT_WINNER_GETS_FIVE, HIGH_POINT_WINNER_GETS_EIGHT, - HIGH_POINT_WINNER_GETS_EIGHT_AND_INTERPOLATION, HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT, HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT, LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07, + HIGH_POINT_WINNER_GETS_EIGHT_AND_INTERPOLATION, HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT, HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT, HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017, LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07, LOW_POINT_LEAGUE_OVERALL, HIGH_POINT_MATCH_RACING, LOW_POINT_TIE_BREAK_BASED_ON_LAST_SERIES_ONLY } diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/MasterDataImportObjectCreationCountImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/MasterDataImportObjectCreationCountImpl.java index 766c00c4751..792c4b42279 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/MasterDataImportObjectCreationCountImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/MasterDataImportObjectCreationCountImpl.java @@ -17,12 +17,12 @@ import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount; * */ public class MasterDataImportObjectCreationCountImpl implements MasterDataImportObjectCreationCount { - private static final long serialVersionUID = -3677005970701170818L; private int leaderboardCount = 0; private int leaderboardGroupCount = 0; private int eventCount = 0; private int regattaCount = 0; + private int mediaTrackCount = 0; private Set createdLeaderboards = new HashSet(); private Set createdLeaderboardGroups = new HashSet(); @@ -52,7 +52,11 @@ public class MasterDataImportObjectCreationCountImpl implements MasterDataImport public void addOneRegatta(String id) { createdRegattas.add(id); regattaCount++; - + } + + @Override + public void addOneMediaTrack() { + mediaTrackCount++; } public void add(MasterDataImportObjectCreationCountImpl toAdd) { @@ -101,6 +105,11 @@ public class MasterDataImportObjectCreationCountImpl implements MasterDataImport public int getRegattaCount() { return regattaCount; } + + @Override + public int getMediaTrackCount() { + return mediaTrackCount; + } @Override public Set getOverwrittenRegattaNames() { diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/WindImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/WindImpl.java index 1ae650de809..516686bd0d7 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/WindImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/WindImpl.java @@ -33,7 +33,7 @@ public class WindImpl extends KnotSpeedWithBearingImpl implements Wind { } public static int hashCode(double latDeg, double lngDeg, long timePointAsMillis) { - return (31 * (int) (timePointAsMillis & Integer.MAX_VALUE)) ^ (int) (latDeg*lngDeg); + return (31 * (int) (timePointAsMillis & Integer.MAX_VALUE)) ^ (int) (Math.round(latDeg)*Math.round(lngDeg)); } /** * Wind hash is determined based on time point and position only to speed this up a little. diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java index d1d2fe16eda..f2fa748442c 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java @@ -69,7 +69,6 @@ public class MediaTrack implements Serializable { Set assignedRaces) { this(title, url, startTime, duration, mimeType, assignedRaces); this.dbId = dbId; - } public String toString() { diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoSensorDataMetadata.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoSensorDataMetadata.java index b7b1b9dd201..5f8d177bf6e 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoSensorDataMetadata.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoSensorDataMetadata.java @@ -14,10 +14,11 @@ public enum BravoSensorDataMetadata { INSTANCE; - private static final String RIDE_HEIGHT_PORT_HULL = "RideHeightPortHull"; - private static final String RIDE_HEIGHT_STBD_HULL = "RideHeightStbdHull"; - private static final String HEEL = "Heel"; - private static final String PITCH = "ImuSensor_Pitch"; + public static final String RIDE_HEIGHT = "RideHeight"; + public static final String RIDE_HEIGHT_PORT_HULL = "RideHeightPortHull"; + public static final String RIDE_HEIGHT_STBD_HULL = "RideHeightStbdHull"; + public static final String HEEL = "Heel"; + public static final String PITCH = "ImuSensor_Pitch"; private final int HEADER_COLUMN_OFFSET = 3; diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactGPSFixImpl.java similarity index 54% rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java rename to java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactGPSFixImpl.java index 16a009c6e86..bfd89ce129e 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactGPSFixImpl.java @@ -1,11 +1,6 @@ package com.sap.sailing.domain.common.tracking.impl; -import com.sap.sailing.domain.common.AbstractBearing; -import com.sap.sailing.domain.common.AbstractPosition; -import com.sap.sailing.domain.common.Bearing; -import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.SpeedWithBearing; -import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.AbstractTimePoint; @@ -21,9 +16,9 @@ import com.sap.sse.common.impl.AbstractTimePoint; * @author Axel Uhl (d043530) * */ -public class CompactGPSFixImpl extends AbstractGPSFixImpl { - private static final long serialVersionUID = 8167588584536992501L; - +public abstract class AbstractCompactGPSFixImpl extends AbstractGPSFixImpl { + private static final long serialVersionUID = 3943572107870245437L; + /** * Bit mask for {@link #whatIsCached}, telling whether validity is currently cached */ @@ -39,9 +34,7 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { * {@link #whatIsCached}&{@link #IS_VALIDITY_CACHED} != 0 */ private static final byte VALIDITY = 1<<2; - - private final double latDeg; - private final double lngDeg; + private final long timePointAsMillis; /** @@ -52,32 +45,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { */ private byte whatIsCached = 0; - /** - * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed's - * true "bearing" (true course over ground) in degrees. - */ - private double cachedEstimatedSpeedBearingInDegrees; - - /** - * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed - * in knots. - */ - private double cachedEstimatedSpeedInKnots; - - public class CompactPosition extends AbstractPosition { - private static final long serialVersionUID = 5621506820766614178L; - - @Override - public double getLatDeg() { - return latDeg; - } - - @Override - public double getLngDeg() { - return lngDeg; - } - } - private class CompactTimePoint extends AbstractTimePoint implements TimePoint { private static final long serialVersionUID = -2470922642359937437L; @@ -87,37 +54,12 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { } } - private class CompactEstimatedSpeedBearing extends AbstractBearing { - private static final long serialVersionUID = 8549231429037883121L; - - @Override - public double getDegrees() { - return cachedEstimatedSpeedBearingInDegrees; - } - } - - private class CompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl { - private static final long serialVersionUID = -5871855443391817248L; - - @Override - public Bearing getBearing() { - return new CompactEstimatedSpeedBearing(); - } - - @Override - public double getKnots() { - return cachedEstimatedSpeedInKnots; - } - } - - public CompactGPSFixImpl(Position position, TimePoint timePoint) { - latDeg = position.getLatDeg(); - lngDeg = position.getLngDeg(); + public AbstractCompactGPSFixImpl(TimePoint timePoint) { timePointAsMillis = timePoint==null?-1:timePoint.asMillis(); } - - public CompactGPSFixImpl(GPSFix gpsFix) { - this(gpsFix.getPosition(), gpsFix.getTimePoint()); + + public AbstractCompactGPSFixImpl(GPSFix gpsFix) { + this(gpsFix.getTimePoint()); } @Override @@ -125,11 +67,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { return getTimePoint() + ": " + getPosition(); } - @Override - public Position getPosition() { - return new CompactPosition(); - } - @Override public TimePoint getTimePoint() { return new CompactTimePoint(); @@ -166,12 +103,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { return (whatIsCached & IS_ESTIMATED_SPEED_CACHED) != 0; } - @Override - public SpeedWithBearing getCachedEstimatedSpeed() { - assert isEstimatedSpeedCached(); - return new CompactEstimatedSpeed(); - } - @Override public void invalidateEstimatedSpeedCache() { whatIsCached &= ~IS_ESTIMATED_SPEED_CACHED; @@ -179,10 +110,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { @Override public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { - cachedEstimatedSpeedBearingInDegrees = estimatedSpeed.getBearing().getDegrees(); - cachedEstimatedSpeedInKnots = estimatedSpeed.getKnots(); whatIsCached |= IS_ESTIMATED_SPEED_CACHED; } - - } diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactGPSFixMovingImpl.java similarity index 66% rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java rename to java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactGPSFixMovingImpl.java index b48f26dcd05..a23e80dd0a3 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactGPSFixMovingImpl.java @@ -1,6 +1,5 @@ package com.sap.sailing.domain.common.tracking.impl; -import com.sap.sailing.domain.common.AbstractBearing; import com.sap.sailing.domain.common.AbstractSpeedImpl; import com.sap.sailing.domain.common.Bearing; import com.sap.sailing.domain.common.CourseChange; @@ -21,23 +20,14 @@ import com.sap.sse.common.TimePoint; * @author Axel Uhl (d043530) * */ -public class CompactGPSFixMovingImpl extends CompactGPSFixImpl implements GPSFixMoving { - private static final long serialVersionUID = 761582024504236533L; - private final double knotSpeed; - private final double degBearing; - - private class CompactSpeedWithBearing extends AbstractSpeedImpl implements SpeedWithBearing { +public abstract class AbstractCompactGPSFixMovingImpl extends AbstractCompactGPSFixImpl implements GPSFixMoving { + private static final long serialVersionUID = 3977983319207618335L; + + protected abstract class AbstractCompactSpeedWithBearing extends AbstractSpeedImpl implements SpeedWithBearing { private static final long serialVersionUID = 1802065090733146728L; @Override - public double getKnots() { - return knotSpeed; - } - - @Override - public Bearing getBearing() { - return new CompactBearing(); - } + public abstract double getKnots(); @Override public Position travelTo(Position pos, TimePoint from, TimePoint to) { @@ -81,33 +71,12 @@ public class CompactGPSFixMovingImpl extends CompactGPSFixImpl implements GPSFix } } - private class CompactBearing extends AbstractBearing { - private static final long serialVersionUID = -6474909210513108635L; - - @Override - public double getDegrees() { - return degBearing; - } - - @Override - public double getRadians() { - return degBearing / 180. * Math.PI; - } + public AbstractCompactGPSFixMovingImpl(TimePoint timePoint) { + super(timePoint); } - public CompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed) { - super(position, timePoint); - knotSpeed = speed.getKnots(); - degBearing = speed.getBearing().getDegrees(); - } - - public CompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) { - this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed()); - } - - @Override - public SpeedWithBearing getSpeed() { - return new CompactSpeedWithBearing(); + public AbstractCompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) throws CompactionNotPossibleException { + this(gpsFixMoving.getTimePoint()); } @Override diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactWindImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactWindImpl.java new file mode 100755 index 00000000000..81c83d7008e --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactWindImpl.java @@ -0,0 +1,129 @@ +package com.sap.sailing.domain.common.tracking.impl; + +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.Wind; +import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; +import com.sap.sailing.domain.common.impl.WindImpl; +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util; +import com.sap.sse.common.impl.AbstractTimePoint; + +public abstract class AbstractCompactWindImpl extends AbstractSpeedWithAbstractBearingImpl implements Wind { + private static final long serialVersionUID = -5059956032663387929L; + + /** + * bit mask for {@link #flags}, telling the bit encoding whether the position is {@code null}. + */ + private static final byte POSITION_IS_NULL = 1<<0; + + /** + * bit mask for {@link #flags}, telling the bit encoding whether the bearing is {@code null}. + */ + private static final byte BEARING_IS_NULL = 1<<1; + + /** + * bit mask for {@link #flags}, telling the bit encoding whether the time point is {@code null}. + */ + private static final byte TIME_POINT_IS_NULL = 1<<2; + + /** + * See the bit mask values such as {@link #POSITION_IS_NULL}, {@link #BEARING_IS_NULL} and {@link #TIME_POINT_IS_NULL}. + */ + private final byte flags; + + private final long timePointAsMillis; + + private class CompactTimePoint extends AbstractTimePoint implements TimePoint { + private static final long serialVersionUID = -2470922642359937437L; + + @Override + public long asMillis() { + return timePointAsMillis; + } + } + + public AbstractCompactWindImpl(Wind wind) { + final boolean bearingIsNull; + final boolean positionIsNull; + final boolean timePointIsNull; + bearingIsNull = wind.getBearing() == null; + positionIsNull = wind.getPosition() == null; + if (wind.getTimePoint() == null) { + timePointIsNull = true; + this.timePointAsMillis = 0; + } else { + timePointIsNull = false; + this.timePointAsMillis = wind.getTimePoint().asMillis(); + } + flags = (byte) ((byte) (bearingIsNull ? BEARING_IS_NULL : (byte) 0) | (positionIsNull ? POSITION_IS_NULL : (byte) 0) | (timePointIsNull ? TIME_POINT_IS_NULL : (byte) 0)); + } + + @Override + public Position getPosition() { + if ((flags & POSITION_IS_NULL) != 0) { + return null; + } else { + return getCompactPosition(); + } + } + + protected abstract Position getCompactPosition(); + + @Override + public TimePoint getTimePoint() { + if ((flags & TIME_POINT_IS_NULL) != 0) { + return null; + } else { + return new CompactTimePoint(); + } + } + + @Override + public Bearing getBearing() { + if ((flags & BEARING_IS_NULL) != 0) { + return null; + } else { + return getCompactBearing(); + } + } + + protected abstract Bearing getCompactBearing(); + + /** + * Make abstract to force implementing subclasses to implement this method. + */ + @Override + public abstract double getKnots(); + + @Override + public Bearing getFrom() { + if (getBearing() == null) { + return null; + } else { + return getBearing().reverse(); + } + } + + @Override + public int hashCode() { + return WindImpl.hashCode(getPosition().getLatDeg(), getPosition().getLngDeg(), (flags&TIME_POINT_IS_NULL) != 0?0:timePointAsMillis); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (!(obj instanceof Wind)) + return false; + Wind other = (Wind) obj; + return Util.equalsWithNull(getPosition(), other.getPosition()) && Util.equalsWithNull(getTimePoint(), other.getTimePoint()); + } + + @Override + public String toString() { + return ""+getTimePoint()+"@"+getPosition()+": "+getKnots()+"kn from "+getFrom(); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactPositionHelper.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactPositionHelper.java new file mode 100755 index 00000000000..b391ca92522 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactPositionHelper.java @@ -0,0 +1,75 @@ +package com.sap.sailing.domain.common.tracking.impl; + +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.Speed; + +/** + * A utility class that "compact" fix implementations such as {@link VeryCompactGPSFixImpl} etc. can use + * to obtain representations of latitudes, longitudes, knot speeds and degree bearings marshalled in + * types that sacrifice very little accuracy from a real-world perspective, yet use a data type for + * encoding that requires fewer bytes than a {@code double} value.

+ * + * Latitude and longitude values are represented using a signed {@code int} value, scaling their range (-90..+90 and + * -180..+180, respectively over the full {@code int} range. This gives a resolution of 4.6mm for latitudes, + * and at the equator of 9.3mm for longitudes.

+ * + * Bearings / courses over ground are represented as a signed {@code short} value, mapping the range of -360..+360 to the + * value range of the {@code short} datatype. This results in a resolution of 0.01.

+ * + * Speed values are represented in knots in their compact form; lossy compaction uses a signed {@code short} value for + * the knot speeds, assuming a range of -500kts..+500kts, spreading this range over the value range of the {@code short} + * datatype. This results in a resolution of 0.015kts.

+ * + * If an attempt is made to obtain a compact form of a knot speed or bearing where the value if out of the range described above, + * a {@link CompactionNotPossibleException} will be thrown. Callers should then transparently resort to the precise + * compaction counterparts for the respective type. + * + * @author Axel Uhl (d043530) + * + */ +public class CompactPositionHelper { + private static final double LAT_SCALE = 90. / (double) (1 << 31); // int + private static final double LNG_SCALE = 180. / (double) (1 << 31); // int + + private static final double KNOT_SPEED_SCALE = 500. /* knots; what that we track would ever be faster? */ / (double) (1<<15); // short + private static final double DEGREE_BEARING_SCALE = 360. / (double) (1<<15); // short + + // Positions + public static double getLatDeg(int latDegScaled) { + return LAT_SCALE * latDegScaled; + } + + public static double getLngDeg(int lngDegScaled) { + return LNG_SCALE * lngDegScaled; + } + + public static int getLngDegScaled(Position position) { + return (int) (position.getLngDeg() / LNG_SCALE); + } + + public static int getLatDegScaled(Position position) { + return (int) (position.getLatDeg() / LAT_SCALE); + } + + // Speeds / Bearings + public static double getKnotSpeed(short knotSpeedScaled) { + return KNOT_SPEED_SCALE * knotSpeedScaled; + } + + public static double getDegreeBearing(short degreeBearingScaled) { + return DEGREE_BEARING_SCALE * degreeBearingScaled; + } + + public static short getKnotSpeedScaled(Speed speed) throws CompactionNotPossibleException { + final double knotSpeedScaled = speed.getKnots() / KNOT_SPEED_SCALE; + if (knotSpeedScaled > Short.MAX_VALUE || knotSpeedScaled < Short.MIN_VALUE) { + throw new CompactionNotPossibleException("Speed "+speed+" cannot be compacted; "+speed.getKnots()+" does not fit into a signed short value"); + } + return (short) knotSpeedScaled; + } + + public static short getDegreeBearingScaled(Bearing bearing) { + return (short) (bearing.getDegrees() / DEGREE_BEARING_SCALE); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactWindImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactWindImpl.java deleted file mode 100755 index 0c0035c54e7..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactWindImpl.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.sap.sailing.domain.common.tracking.impl; - -import com.sap.sailing.domain.common.AbstractBearing; -import com.sap.sailing.domain.common.AbstractPosition; -import com.sap.sailing.domain.common.Bearing; -import com.sap.sailing.domain.common.Position; -import com.sap.sailing.domain.common.Wind; -import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; -import com.sap.sailing.domain.common.impl.WindImpl; -import com.sap.sse.common.TimePoint; -import com.sap.sse.common.Util; -import com.sap.sse.common.impl.AbstractTimePoint; - -public class CompactWindImpl extends AbstractSpeedWithAbstractBearingImpl implements Wind { - private static final long serialVersionUID = -5059956032663387929L; - private final double latDeg; - private final double lngDeg; - private final boolean positionIsNull; - private final boolean bearingIsNull; - private final boolean timePointIsNull; - private final double speedInKnots; - private final double degBearing; - private final long timePointAsMillis; - - public class CompactPosition extends AbstractPosition { - private static final long serialVersionUID = 5621506820766614178L; - - @Override - public double getLatDeg() { - return latDeg; - } - - @Override - public double getLngDeg() { - return lngDeg; - } - - @Override - public boolean equals(Object o) { - return this==o || o instanceof Position && getLatDeg() == ((Position) o).getLatDeg() && getLngDeg() == ((Position) o).getLngDeg(); - } - } - - private class CompactBearing extends AbstractBearing { - private static final long serialVersionUID = -6474909210513108635L; - - @Override - public double getDegrees() { - return degBearing; - } - - @Override - public double getRadians() { - return degBearing / 180. * Math.PI; - } - - @Override - public boolean equals(Object object) { - return this==object || object instanceof Bearing && getDegrees() == ((Bearing) object).getDegrees(); - } - } - - private class CompactTimePoint extends AbstractTimePoint implements TimePoint { - private static final long serialVersionUID = -2470922642359937437L; - - @Override - public long asMillis() { - return timePointAsMillis; - } - } - - public CompactWindImpl(Wind wind) { - if (wind.getBearing() == null) { - bearingIsNull = true; - degBearing = 0; - } else { - this.degBearing = wind.getBearing().getDegrees(); - bearingIsNull = false; - } - if (wind.getPosition() == null) { - positionIsNull = true; - this.latDeg = 0; - this.lngDeg = 0; - } else { - this.latDeg = wind.getPosition().getLatDeg(); - this.lngDeg = wind.getPosition().getLngDeg(); - positionIsNull = false; - } - this.speedInKnots = wind.getKnots(); - if (wind.getTimePoint() == null) { - timePointIsNull = true; - this.timePointAsMillis = 0; - } else { - timePointIsNull = false; - this.timePointAsMillis = wind.getTimePoint().asMillis(); - } - } - - @Override - public Position getPosition() { - if (positionIsNull) { - return null; - } else { - return new CompactPosition(); - } - } - - @Override - public TimePoint getTimePoint() { - if (timePointIsNull) { - return null; - } else { - return new CompactTimePoint(); - } - } - - @Override - public Bearing getBearing() { - if (bearingIsNull) { - return null; - } else { - return new CompactBearing(); - } - } - - @Override - public double getKnots() { - return speedInKnots; - } - - @Override - public Bearing getFrom() { - if (getBearing() == null) { - return null; - } else { - return getBearing().reverse(); - } - } - - @Override - public int hashCode() { - return WindImpl.hashCode(latDeg, lngDeg, timePointIsNull?0:timePointAsMillis); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (!(obj instanceof Wind)) - return false; - Wind other = (Wind) obj; - return Util.equalsWithNull(getPosition(), other.getPosition()) && Util.equalsWithNull(getTimePoint(), other.getTimePoint()); - } - - @Override - public String toString() { - return ""+getTimePoint()+"@"+getPosition()+": "+getKnots()+"kn from "+getFrom(); - } -} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactionNotPossibleException.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactionNotPossibleException.java new file mode 100755 index 00000000000..43be75fd2d0 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactionNotPossibleException.java @@ -0,0 +1,37 @@ +package com.sap.sailing.domain.common.tracking.impl; + +/** + * Throws when an attempt is made to turn a fix of some sort into a more compact form, probably + * slightly reducing accuracy and/or reducing value ranges, such as for the speeds possible, where + * the fix presented cannot be turned into its compact form without exceeding a range. This would + * lead to an overflow or wrap-around and cannot be tolerated. Clients need to handle this exception + * by skipping compaction and using the original fix instead. + * + * @author Axel Uhl (d043530) + * + */ +public class CompactionNotPossibleException extends Exception { + private static final long serialVersionUID = -723044264487667717L; + + public CompactionNotPossibleException() { + super(); + } + + public CompactionNotPossibleException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public CompactionNotPossibleException(String message, Throwable cause) { + super(message, cause); + } + + public CompactionNotPossibleException(String message) { + super(message); + } + + public CompactionNotPossibleException(Throwable cause) { + super(cause); + } + +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixImpl.java new file mode 100755 index 00000000000..1cf8940a462 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixImpl.java @@ -0,0 +1,105 @@ +package com.sap.sailing.domain.common.tracking.impl; + +import com.sap.sailing.domain.common.AbstractBearing; +import com.sap.sailing.domain.common.AbstractPosition; +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; +import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sse.common.TimePoint; + +/** + * A compact representation of a GPS fix which collects all primitive-typed attributes in one object to avoid + * memory overhead otherwise created by using too many individual fine-grained objects.

+ * + * Objects of this type are assumed to be contained in at most one {@link DynamicGPSFixTrackImpl}. It is + * therefore permissible to cache information about validity to speed up the otherwise expensive + * {@link DynamicGPSFixTrackImpl#isValid(PartialNavigableSetView, GPSFix)} computation. + * + * @author Axel Uhl (d043530) + * + */ +public class PreciseCompactGPSFixImpl extends AbstractCompactGPSFixImpl { + private static final long serialVersionUID = 8167588584536992501L; + + private final double latDeg; + private final double lngDeg; + + /** + * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed's + * true "bearing" (true course over ground) in degrees. + */ + private double cachedEstimatedSpeedBearingInDegrees; + + /** + * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed + * in knots. + */ + private double cachedEstimatedSpeedInKnots; + + public class PreciseCompactPosition extends AbstractPosition { + private static final long serialVersionUID = 5621506820766614178L; + + @Override + public double getLatDeg() { + return latDeg; + } + + @Override + public double getLngDeg() { + return lngDeg; + } + } + + private class PreciseCompactEstimatedSpeedBearing extends AbstractBearing { + private static final long serialVersionUID = 8549231429037883121L; + + @Override + public double getDegrees() { + return cachedEstimatedSpeedBearingInDegrees; + } + } + + private class PreciseCompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl { + private static final long serialVersionUID = -5871855443391817248L; + + @Override + public Bearing getBearing() { + return new PreciseCompactEstimatedSpeedBearing(); + } + + @Override + public double getKnots() { + return cachedEstimatedSpeedInKnots; + } + } + + public PreciseCompactGPSFixImpl(Position position, TimePoint timePoint) { + super(timePoint); + latDeg = position.getLatDeg(); + lngDeg = position.getLngDeg(); + } + + public PreciseCompactGPSFixImpl(GPSFix gpsFix) { + this(gpsFix.getPosition(), gpsFix.getTimePoint()); + } + + @Override + public Position getPosition() { + return new PreciseCompactPosition(); + } + + @Override + public SpeedWithBearing getCachedEstimatedSpeed() { + assert isEstimatedSpeedCached(); + return new PreciseCompactEstimatedSpeed(); + } + + @Override + public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { + cachedEstimatedSpeedBearingInDegrees = estimatedSpeed.getBearing().getDegrees(); + cachedEstimatedSpeedInKnots = estimatedSpeed.getKnots(); + super.cacheEstimatedSpeed(estimatedSpeed); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixMovingImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixMovingImpl.java new file mode 100755 index 00000000000..cc6944a24b9 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixMovingImpl.java @@ -0,0 +1,135 @@ +package com.sap.sailing.domain.common.tracking.impl; + +import com.sap.sailing.domain.common.AbstractBearing; +import com.sap.sailing.domain.common.AbstractPosition; +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; +import com.sap.sailing.domain.common.tracking.GPSFixMoving; +import com.sap.sse.common.TimePoint; + +/** + * A memory-conserving representation of a {@link GPSFixMoving} object that produces the fine-grained + * objects for {@link Position}, {@link SpeedWithBearing}, {@link Bearing} and {@link TimePoint} dynamically + * as thin wrappers around this object which holds all elementary attributes required. This saves several + * object references and object headers. + * + * @author Axel Uhl (d043530) + * + */ +public class PreciseCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingImpl { + private static final long serialVersionUID = 761582024504236533L; + private final double latDeg; + private final double lngDeg; + private final double knotSpeed; + private final double degBearing; + + /** + * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed's + * true "bearing" (true course over ground) in degrees. + */ + private double cachedEstimatedSpeedBearingInDegrees; + + /** + * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed + * in knots. + */ + private double cachedEstimatedSpeedInKnots; + + + private class PreciseCompactSpeedWithBearing extends AbstractCompactSpeedWithBearing implements SpeedWithBearing { + private static final long serialVersionUID = 1802065090733146728L; + + @Override + public double getKnots() { + return knotSpeed; + } + + @Override + public Bearing getBearing() { + return new PreciseCompactBearing(); + } + } + + private class PreciseCompactBearing extends AbstractBearing { + private static final long serialVersionUID = -6474909210513108635L; + + @Override + public double getDegrees() { + return degBearing; + } + } + + public class PreciseCompactPosition extends AbstractPosition { + private static final long serialVersionUID = 5621506820766614178L; + + @Override + public double getLatDeg() { + return latDeg; + } + + @Override + public double getLngDeg() { + return lngDeg; + } + } + + private class PreciseCompactEstimatedSpeedBearing extends AbstractBearing { + private static final long serialVersionUID = 8549231429037883121L; + + @Override + public double getDegrees() { + return cachedEstimatedSpeedBearingInDegrees; + } + } + + private class PreciseCompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl { + private static final long serialVersionUID = -5871855443391817248L; + + @Override + public Bearing getBearing() { + return new PreciseCompactEstimatedSpeedBearing(); + } + + @Override + public double getKnots() { + return cachedEstimatedSpeedInKnots; + } + } + + public PreciseCompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed) { + super(timePoint); + latDeg = position.getLatDeg(); + lngDeg = position.getLngDeg(); + knotSpeed = speed==null?0:speed.getKnots(); + degBearing = speed==null?0:speed.getBearing().getDegrees(); + } + + public PreciseCompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) { + this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed()); + } + + @Override + public SpeedWithBearing getSpeed() { + return new PreciseCompactSpeedWithBearing(); + } + + @Override + public Position getPosition() { + return new PreciseCompactPosition(); + } + + @Override + public SpeedWithBearing getCachedEstimatedSpeed() { + assert isEstimatedSpeedCached(); + return new PreciseCompactEstimatedSpeed(); + } + + @Override + public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { + cachedEstimatedSpeedBearingInDegrees = estimatedSpeed.getBearing().getDegrees(); + cachedEstimatedSpeedInKnots = estimatedSpeed.getKnots(); + super.cacheEstimatedSpeed(estimatedSpeed); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactWindImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactWindImpl.java new file mode 100755 index 00000000000..12a444c2cb2 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactWindImpl.java @@ -0,0 +1,81 @@ +package com.sap.sailing.domain.common.tracking.impl; + +import com.sap.sailing.domain.common.AbstractBearing; +import com.sap.sailing.domain.common.AbstractPosition; +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.Wind; + +/** + * Keeps the precise values of lat/lng and speed/course. + * + * @author Axel Uhl (d043530) + * + */ +public class PreciseCompactWindImpl extends AbstractCompactWindImpl { + private static final long serialVersionUID = -5059956032663387929L; + private final double latDeg; + private final double lngDeg; + private final double speedInKnots; + private final double degBearing; + + public class CompactPosition extends AbstractPosition { + private static final long serialVersionUID = 5621506820766614178L; + + @Override + public double getLatDeg() { + return latDeg; + } + + @Override + public double getLngDeg() { + return lngDeg; + } + + @Override + public boolean equals(Object o) { + return this==o || o instanceof Position && getLatDeg() == ((Position) o).getLatDeg() && getLngDeg() == ((Position) o).getLngDeg(); + } + } + + private class CompactBearing extends AbstractBearing { + private static final long serialVersionUID = -6474909210513108635L; + + @Override + public double getDegrees() { + return degBearing; + } + } + + public PreciseCompactWindImpl(Wind wind) { + super(wind); + if (wind.getBearing() == null) { + degBearing = 0; + } else { + this.degBearing = wind.getBearing().getDegrees(); + } + if (wind.getPosition() == null) { + this.latDeg = 0; + this.lngDeg = 0; + } else { + this.latDeg = wind.getPosition().getLatDeg(); + this.lngDeg = wind.getPosition().getLngDeg(); + } + this.speedInKnots = wind.getKnots(); + } + + @Override + public double getKnots() { + return speedInKnots; + } + + @Override + protected Position getCompactPosition() { + return new CompactPosition(); + } + + @Override + protected Bearing getCompactBearing() { + return new CompactBearing(); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixImpl.java new file mode 100755 index 00000000000..ff6b0931d43 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixImpl.java @@ -0,0 +1,128 @@ +package com.sap.sailing.domain.common.tracking.impl; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.sap.sailing.domain.common.AbstractBearing; +import com.sap.sailing.domain.common.AbstractPosition; +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; +import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sse.common.TimePoint; + +/** + * A compact representation of a GPS fix which collects all primitive-typed attributes in one object to avoid + * memory overhead otherwise created by using too many individual fine-grained objects.

+ * + * Objects of this type are assumed to be contained in at most one {@link DynamicGPSFixTrackImpl}. It is + * therefore permissible to cache information about validity to speed up the otherwise expensive + * {@link DynamicGPSFixTrackImpl#isValid(PartialNavigableSetView, GPSFix)} computation. + * + * @author Axel Uhl (d043530) + * + */ +public class VeryCompactGPSFixImpl extends AbstractCompactGPSFixImpl { + private static final long serialVersionUID = 3943572107870245437L; + + private static final Logger logger = Logger.getLogger(VeryCompactGPSFixImpl.class.getName()); + + /** + * See {@link CompactPositionHelper} + */ + private final int latDegScaled; + + /** + * See {@link CompactPositionHelper} + */ + private final int lngDegScaled; + + /** + * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed's + * true "bearing" (true course over ground) in degrees, scaled into a short value using {@link CompactPositionHelper}. + */ + private short cachedEstimatedSpeedBearingInDegreesScaled; + + /** + * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed + * in knots, scaled into a short value using {@link CompactPositionHelper}. + */ + private short cachedEstimatedSpeedInKnotsScaled; + + public class CompactPosition extends AbstractPosition { + private static final long serialVersionUID = 5621506820766614178L; + + @Override + public double getLatDeg() { + return CompactPositionHelper.getLatDeg(latDegScaled); + } + + @Override + public double getLngDeg() { + return CompactPositionHelper.getLngDeg(lngDegScaled); + } + } + + private class VeryCompactEstimatedSpeedBearing extends AbstractBearing { + private static final long serialVersionUID = 8549231429037883121L; + + @Override + public double getDegrees() { + return CompactPositionHelper.getDegreeBearing(cachedEstimatedSpeedBearingInDegreesScaled); + } + } + + private class VeryCompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl { + private static final long serialVersionUID = -5871855443391817248L; + + @Override + public Bearing getBearing() { + return new VeryCompactEstimatedSpeedBearing(); + } + + @Override + public double getKnots() { + return CompactPositionHelper.getKnotSpeed(cachedEstimatedSpeedInKnotsScaled); + } + } + + public VeryCompactGPSFixImpl(Position position, TimePoint timePoint) { + super(timePoint); + latDegScaled = CompactPositionHelper.getLatDegScaled(position); + lngDegScaled = CompactPositionHelper.getLngDegScaled(position); + } + + public VeryCompactGPSFixImpl(GPSFix gpsFix) { + this(gpsFix.getPosition(), gpsFix.getTimePoint()); + } + + @Override + public Position getPosition() { + return new CompactPosition(); + } + + @Override + public SpeedWithBearing getCachedEstimatedSpeed() { + assert isEstimatedSpeedCached(); + return new VeryCompactEstimatedSpeed(); + } + + /** + * Under rare circumstances, caching the speed may fail for the compact representation of a GPS fix. + * This can happen if the speed estimated exceeds the range that can be represented in this compact + * form which is less than in the original form where the speed amount is represented as a {@code double} + * value. In this case, a warning message is logged with level {@link Level#FINER}, and the speed remains + * uncached. + */ + @Override + public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { + try { + cachedEstimatedSpeedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(estimatedSpeed); + cachedEstimatedSpeedBearingInDegreesScaled = CompactPositionHelper.getDegreeBearingScaled(estimatedSpeed.getBearing()); + super.cacheEstimatedSpeed(estimatedSpeed); + } catch (CompactionNotPossibleException e) { + logger.log(Level.FINER, "Cannot cache estimated speed "+estimatedSpeed+" in compact fix:", e); + } + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixMovingImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixMovingImpl.java new file mode 100755 index 00000000000..625379af503 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixMovingImpl.java @@ -0,0 +1,171 @@ +package com.sap.sailing.domain.common.tracking.impl; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.sap.sailing.domain.common.AbstractBearing; +import com.sap.sailing.domain.common.AbstractPosition; +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; +import com.sap.sailing.domain.common.tracking.GPSFixMoving; +import com.sap.sse.common.TimePoint; + +/** + * A memory-conserving representation of a {@link GPSFixMoving} object that produces the fine-grained + * objects for {@link Position}, {@link SpeedWithBearing}, {@link Bearing} and {@link TimePoint} dynamically + * as thin wrappers around this object which holds all elementary attributes required. This saves several + * object references and object headers. + * + * @author Axel Uhl (d043530) + * + */ +public class VeryCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingImpl { + private static final long serialVersionUID = 3977983319207618335L; + + private static final Logger logger = Logger.getLogger(VeryCompactGPSFixMovingImpl.class.getName()); + + /** + * See {@link CompactPositionHelper} + */ + private final int latDegScaled; + + /** + * See {@link CompactPositionHelper} + */ + private final int lngDegScaled; + + /** + * See {@link CompactPositionHelper} + */ + private final short speedInKnotsScaled; + + /** + * See {@link CompactPositionHelper} + */ + private final short degreeBearingScaled; + + /** + * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed's + * true "bearing" (true course over ground) in degrees, scaled into a short value using {@link CompactPositionHelper}. + */ + private short cachedEstimatedSpeedBearingInDegreesScaled; + + /** + * When {@link #whatIsCached}&{@link #IS_ESTIMATED_SPEED_CACHED} != 0, this field tells the estimated speed + * in knots, scaled into a short value using {@link CompactPositionHelper}. + */ + private short cachedEstimatedSpeedInKnotsScaled; + + public class VeryCompactPosition extends AbstractPosition { + private static final long serialVersionUID = 5621506820766614178L; + + @Override + public double getLatDeg() { + return CompactPositionHelper.getLatDeg(latDegScaled); + } + + @Override + public double getLngDeg() { + return CompactPositionHelper.getLngDeg(lngDegScaled); + } + } + + private class VeryCompactSpeedWithBearing extends AbstractCompactSpeedWithBearing { + private static final long serialVersionUID = 1802065090733146728L; + + @Override + public double getKnots() { + return CompactPositionHelper.getKnotSpeed(speedInKnotsScaled); + } + + @Override + public Bearing getBearing() { + return new VeryCompactBearing(); + } + } + + private class VeryCompactBearing extends AbstractBearing { + private static final long serialVersionUID = 8167886382067060570L; + + @Override + public double getDegrees() { + return CompactPositionHelper.getDegreeBearing(degreeBearingScaled); + } + } + + private class VeryCompactEstimatedSpeedBearing extends AbstractBearing { + private static final long serialVersionUID = 8549231429037883121L; + + @Override + public double getDegrees() { + return CompactPositionHelper.getDegreeBearing(cachedEstimatedSpeedBearingInDegreesScaled); + } + } + + private class VeryCompactEstimatedSpeed extends AbstractSpeedWithAbstractBearingImpl { + private static final long serialVersionUID = -5871855443391817248L; + + @Override + public Bearing getBearing() { + return new VeryCompactEstimatedSpeedBearing(); + } + + @Override + public double getKnots() { + return CompactPositionHelper.getKnotSpeed(cachedEstimatedSpeedInKnotsScaled); + } + } + + public VeryCompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed) throws CompactionNotPossibleException { + super(timePoint); + latDegScaled = CompactPositionHelper.getLatDegScaled(position); + lngDegScaled = CompactPositionHelper.getLngDegScaled(position); + if (speed == null) { + speedInKnotsScaled = 0; + degreeBearingScaled = 0; + } else { + speedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(speed); + degreeBearingScaled = CompactPositionHelper.getDegreeBearingScaled(speed.getBearing()); + } + } + + public VeryCompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) throws CompactionNotPossibleException { + this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed()); + } + + @Override + public SpeedWithBearing getSpeed() { + return new VeryCompactSpeedWithBearing(); + } + + @Override + public Position getPosition() { + return new VeryCompactPosition(); + } + + @Override + public SpeedWithBearing getCachedEstimatedSpeed() { + assert isEstimatedSpeedCached(); + return new VeryCompactEstimatedSpeed(); + } + + /** + * Under rare circumstances, caching the speed may fail for the compact representation of a GPS fix. + * This can happen if the speed estimated exceeds the range that can be represented in this compact + * form which is less than in the original form where the speed amount is represented as a {@code double} + * value. In this case, a warning message is logged with level {@link Level#FINER}, and the speed remains + * uncached. + */ + @Override + public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { + try { + cachedEstimatedSpeedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(estimatedSpeed); + cachedEstimatedSpeedBearingInDegreesScaled = CompactPositionHelper.getDegreeBearingScaled(estimatedSpeed.getBearing()); + super.cacheEstimatedSpeed(estimatedSpeed); + } catch (CompactionNotPossibleException e) { + logger.log(Level.FINER, "Cannot cache estimated speed "+estimatedSpeed+" in compact fix:", e); + } + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactWindImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactWindImpl.java new file mode 100755 index 00000000000..1d3b60b3988 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactWindImpl.java @@ -0,0 +1,92 @@ +package com.sap.sailing.domain.common.tracking.impl; + +import com.sap.sailing.domain.common.AbstractBearing; +import com.sap.sailing.domain.common.AbstractPosition; +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.Wind; + +/** + * Uses scaled, rounded internal representations of the values for lat/lng and speed/course. See + * {@link CompactPositionHelper} for the details of how value ranges and accuracies are affected. + * + * @author Axel Uhl (d043530) + * + */ +public class VeryCompactWindImpl extends AbstractCompactWindImpl { + private static final long serialVersionUID = -5059956032663387929L; + /** + * See {@link CompactPositionHelper} + */ + private final int latDegScaled; + + /** + * See {@link CompactPositionHelper} + */ + private final int lngDegScaled; + + /** + * See {@link CompactPositionHelper} + */ + private final short speedInKnotsScaled; + + /** + * See {@link CompactPositionHelper} + */ + private final short degreeBearingScaled; + + public class VeryCompactPosition extends AbstractPosition { + private static final long serialVersionUID = 5621506820766614178L; + + @Override + public double getLatDeg() { + return CompactPositionHelper.getLatDeg(latDegScaled); + } + + @Override + public double getLngDeg() { + return CompactPositionHelper.getLngDeg(lngDegScaled); + } + } + + private class VeryCompactBearing extends AbstractBearing { + private static final long serialVersionUID = -6474909210513108635L; + + @Override + public double getDegrees() { + return CompactPositionHelper.getDegreeBearing(degreeBearingScaled); + } + } + + public VeryCompactWindImpl(Wind wind) throws CompactionNotPossibleException { + super(wind); + if (wind.getBearing() == null) { + degreeBearingScaled = 0; + } else { + this.degreeBearingScaled = CompactPositionHelper.getDegreeBearingScaled(wind.getBearing()); + } + if (wind.getPosition() == null) { + this.latDegScaled = 0; + this.lngDegScaled = 0; + } else { + this.latDegScaled = CompactPositionHelper.getLatDegScaled(wind.getPosition()); + this.lngDegScaled = CompactPositionHelper.getLngDegScaled(wind.getPosition()); + } + this.speedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(wind); + } + + @Override + public double getKnots() { + return CompactPositionHelper.getKnotSpeed(speedInKnotsScaled); + } + + @Override + protected Position getCompactPosition() { + return new VeryCompactPosition(); + } + + @Override + protected Bearing getCompactBearing() { + return new VeryCompactBearing(); + } +} diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 84b317d9e5c..fad4cdaf86a 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -1962,7 +1962,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { if (controlPointClass.equals(Mark.class.getSimpleName())) { Mark mark = loadMark((DBObject) dbObject.get(FieldNames.CONTROLPOINT_VALUE.name())); controlPoint = mark; - } else if(controlPointClass.equals("Gate")) { + } else if (controlPointClass.equals("Gate")) { ControlPointWithTwoMarks cpwtm = loadControlPointWithTwoMarks((DBObject) dbObject.get(FieldNames.CONTROLPOINT_VALUE.name())); dbObject.put(FieldNames.CONTROLPOINT_CLASS.name(), ControlPointWithTwoMarks.class.getSimpleName()); controlPoint = cpwtm; @@ -2318,8 +2318,14 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } } try { - callback.accept(connectivityParamsPersistenceService.mapTo(map)); - logger.info("Done restoring race #"+ finalI +"/"+count+" of type "+type); + final RaceTrackingConnectivityParameters params = connectivityParamsPersistenceService.mapTo(map); + if (params != null) { + callback.accept(params); + logger.info("Done restoring race #"+ finalI +"/"+count+" of type "+type); + } else { + logger.warning("Couldn't restore race #"+ finalI +"/"+count+" of type "+type+ + " because the parameters loaded from the DB couldn't be mapped. Maybe the owning leaderboard was removed?"); + } } catch (Exception e) { logger.log(Level.SEVERE, "Exception trying to load race #"+ finalI +"/"+count+" of type "+type+ " from restore connectivity parameters " diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index 575635388ba..891e6dc15cc 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -221,7 +221,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { public DBCollection getWindTrackCollection() { DBCollection result = database.getCollection(CollectionNames.WIND_TRACKS.name()); - result.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), null)); + result.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), 1)); return result; } @@ -237,7 +237,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { public DBCollection getGPSFixMetadataCollection() { DBCollection collection = database.getCollection(CollectionNames.GPS_FIXES_METADATA.name()); DBObject index = new BasicDBObject(); - index.put(FieldNames.DEVICE_ID.name(), null); + index.put(FieldNames.DEVICE_ID.name(), 1); collection.createIndex(index); return collection; } @@ -741,7 +741,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { public DBCollection getRaceLogCollection() { DBCollection result = database.getCollection(CollectionNames.RACE_LOGS.name()); - result.createIndex(new BasicDBObject(FieldNames.RACE_LOG_IDENTIFIER.name(), null)); + result.createIndex(new BasicDBObject(FieldNames.RACE_LOG_IDENTIFIER.name(), 1)); return result; } @@ -1372,8 +1372,8 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { public DBCollection getRegattaLogCollection() { DBCollection result = database.getCollection(CollectionNames.REGATTA_LOGS.name()); - DBObject index = new BasicDBObject(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), null); - index.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), null); + DBObject index = new BasicDBObject(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), 1); + index.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), 1); result.createIndex(index); return result; } diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java index 2e7f4e17d99..aaafe78372d 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java @@ -566,8 +566,7 @@ public class SensorFixStoreAndLoadTest { public static final String TRACK_NAME = "TestFixTrack"; public TestFixTrackImpl(ItemType trackedItem, String trackName) { - super(trackedItem, trackName, TestFixImpl.COLUMNS, - TRACK_NAME + " for " + trackedItem); + super(trackedItem, trackName, TRACK_NAME + " for " + trackedItem); } public Double getTextValue(TimePoint timePoint) { diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/MockGPSFixMongoServiceFinder.java b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/MockGPSFixMongoServiceFinder.java index 241b5fff5f3..b29d32db4b8 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/MockGPSFixMongoServiceFinder.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/MockGPSFixMongoServiceFinder.java @@ -4,8 +4,8 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl; -import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl; import com.sap.sailing.domain.common.tracking.impl.DoubleVectorFixImpl; import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl; @@ -26,9 +26,9 @@ public class MockGPSFixMongoServiceFinder extends AbstractTypeBasedServiceFinder @Override public FixMongoHandler findService(String fixType) { if (fixType.equals(GPSFixMovingImpl.class.getName()) || - fixType.equals(CompactGPSFixMovingImpl.class.getName())) return movingHandler; + fixType.equals(VeryCompactGPSFixMovingImpl.class.getName())) return movingHandler; if (fixType.equals(GPSFixImpl.class.getName()) || - fixType.equals(CompactGPSFixImpl.class.getName())) return handler; + fixType.equals(VeryCompactGPSFixImpl.class.getName())) return handler; if (fixType.equals(DoubleVectorFixImpl.class.getName())) return doubleVectorFixHandler; return null; } diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties b/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties index b0171dd4f67..46bc5fd7db1 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties @@ -5,7 +5,7 @@ iOSUsers=Start iOS App androidUsers=Start Android App alternativelyVisitThisLink=If you are reading this mail on the device with the App already installed, simply click below to start: buoyTender=buoy tender -appStoreInstallText=If you don't have the App yet, please install: +appStoreInstallText=If you don''t have the App yet, please install: appIos=Install iOS App appAndroid=Install Android App buoyPingerAppName=SAP Sailing Buoy Pinger diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages_de.properties b/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages_de.properties index dd6e394c6fc..59d987ee6be 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages_de.properties +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages_de.properties @@ -1,11 +1,11 @@ -trackingInvitationFor=Einladung zum Tracken fr +trackingInvitationFor=Einladung zum Tracken für scanQRCodeOrVisitUrlToRegisterAs=Installiere die {0} App. Dann scanne den QRCode oder klicke den Link mit deinem Smartphone an, um dich zu registrieren als welcomeTo=Willkommen zu iOSUsers=iOS App starten androidUsers=Android App starten -alternativelyVisitThisLink=Wenn die App bereits installiert ist, und du diese Mail auch auf dem Gerte offen hast, dann einfach hier clicken: +alternativelyVisitThisLink=Wenn die App bereits installiert ist, und du diese Mail auch auf dem Geräte offen hast, dann einfach hier clicken: buoyTender=Bojenleger -appStoreInstallText=Falls die App noch nicht installiert ist, kannst du sie hier finden: +appStoreInstallText=Falls die App noch nicht installiert ist, kannst du sie hier finden:Ÿ appIos=iOS App installieren appAndroid=Android App installieren buoyPingerAppName=SAP Sailing Buoy Pinger diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParamsHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParamsHandler.java index e3ef23fa681..b18a8638196 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParamsHandler.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParamsHandler.java @@ -49,12 +49,22 @@ public class RaceLogConnectivityParamsHandler extends AbstractRaceTrackingConnec @Override public RaceTrackingConnectivityParameters mapTo(Map map) throws MalformedURLException, URISyntaxException { + final RaceTrackingConnectivityParameters result; final RegattaLeaderboard leaderboard = (RegattaLeaderboard) racingEventService.getLeaderboardByName((String) map.get(LEADERBOARD_NAME)); - final RaceColumn raceColumn = leaderboard.getRaceColumnByName((String) map.get(RACE_COLUMN_NAME)); - return new RaceLogConnectivityParams(racingEventService, leaderboard.getRegatta(), raceColumn, - raceColumn.getFleetByName((String) map.get(FLEET_NAME)), leaderboard, - ((Number) map.get(DELAY_TO_LIVE_IN_MILLIS)).longValue(), domainFactory, isTrackWind(map), - isCorrectWindDirectionByMagneticDeclination(map)); + if (leaderboard == null) { + result = null; + } else { + final RaceColumn raceColumn = leaderboard.getRaceColumnByName((String) map.get(RACE_COLUMN_NAME)); + if (raceColumn == null) { + result = null; + } else { + result = new RaceLogConnectivityParams(racingEventService, leaderboard.getRegatta(), raceColumn, + raceColumn.getFleetByName((String) map.get(FLEET_NAME)), leaderboard, + ((Number) map.get(DELAY_TO_LIVE_IN_MILLIS)).longValue(), domainFactory, isTrackWind(map), + isCorrectWindDirectionByMagneticDeclination(map)); + } + } + return result; } @Override diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingI18n.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingI18n.java index 0a3fa3a6876..5fc6497003b 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingI18n.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingI18n.java @@ -1,5 +1,7 @@ package com.sap.sailing.domain.racelogtracking.impl; +import java.nio.charset.StandardCharsets; + import com.sap.sse.i18n.ResourceBundleStringMessages; import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl; @@ -7,5 +9,5 @@ public class RaceLogTrackingI18n { private static final String RESOURCE_BASE_NAME = "stringmessages/TrackingStringMessages"; public static final ResourceBundleStringMessages STRING_MESSAGES = new ResourceBundleStringMessagesImpl( - RESOURCE_BASE_NAME, RaceLogTrackingI18n.class.getClassLoader()); + RESOURCE_BASE_NAME, RaceLogTrackingI18n.class.getClassLoader(), StandardCharsets.UTF_8.name()); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/impl/AllEventsOfTypeFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/impl/AllEventsOfTypeFinder.java index 0608dbba198..27250399856 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/impl/AllEventsOfTypeFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/impl/AllEventsOfTypeFinder.java @@ -17,8 +17,8 @@ VisitorT> extends BaseLogAnalyzer> { private final Class ofType; private final boolean onlyUnrevoked; - public AllEventsOfTypeFinder(LogT raceLog, boolean onlyUnrevoked, Class ofType) { - super(raceLog); + public AllEventsOfTypeFinder(LogT log, boolean onlyUnrevoked, Class ofType) { + super(log); this.ofType = ofType; this.onlyUnrevoked = onlyUnrevoked; } diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayService.java b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayService.java index 2553cc2d0d0..40347ac6d11 100755 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayService.java +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayService.java @@ -35,14 +35,10 @@ public interface SwissTimingReplayService { * @param link * the URL without the implicit "http://" prefix, as obtained, e.g., from * {@link SwissTimingReplayRace#getLink()}. - * @param raceName TODO * @param raceID * the SwissTiming ID for the race - * @param trackerManager TODO * @param useInternalMarkPassingAlgorithm * use our own instead of the SwissTiming-provided mark rounding / split times - * @param raceLogStore TODO - * @param regattaLogStore TODO * @param boatClassNameName * only required if {@code regattaToAddTo} is {@code null}; used for the retrieval/creation of a default * regatta diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/AbstractTracTracLiveTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/AbstractTracTracLiveTest.java index e5acc80daf5..4a6fced0e2b 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/AbstractTracTracLiveTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/AbstractTracTracLiveTest.java @@ -25,6 +25,7 @@ import com.sap.sailing.domain.tractracadapter.Receiver; import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants; import com.sap.sailing.domain.tractracadapter.TracTracControlPoint; import com.sap.sailing.domain.tractracadapter.impl.ControlPointAdapter; +import com.sap.sse.common.Duration; import com.sap.sse.common.Util.Pair; import com.tractrac.model.lib.api.ModelLocator; import com.tractrac.model.lib.api.event.CreateModelException; @@ -36,6 +37,7 @@ import com.tractrac.subscription.lib.api.IRaceSubscriber; import com.tractrac.subscription.lib.api.ISubscriberFactory; import com.tractrac.subscription.lib.api.SubscriberInitializationException; import com.tractrac.subscription.lib.api.SubscriptionLocator; +import com.tractrac.util.lib.api.exceptions.TimeOutException; /** * Subclassing tests have to call {@link #addListenersForStoredDataAndStartController(Iterable)} to kick off @@ -65,6 +67,7 @@ public abstract class AbstractTracTracLiveTest extends StoredTrackBasedTest { * Default set-up for an STG training session in Weymouth, 2011 * @throws SubscriberInitializationException * @throws CreateModelException + * @throws TimeOutException */ @Before public void setUp() throws MalformedURLException, IOException, InterruptedException, URISyntaxException, SubscriberInitializationException, ParseException, CreateModelException { @@ -95,26 +98,30 @@ public abstract class AbstractTracTracLiveTest extends StoredTrackBasedTest { protected void setUp(URL paramUrl, URI liveUri, URI storedUri) throws FileNotFoundException, MalformedURLException, URISyntaxException, SubscriberInitializationException, CreateModelException { // Read event data from configuration file - final IRace race = ModelLocator.getEventFactory().createRace(new URI(paramUrl.toString())); - this.race = race; - ISubscriberFactory subscriberFactory = SubscriptionLocator.getSusbcriberFactory(); - if (storedUri == null) { - eventSubscriber = subscriberFactory.createEventSubscriber(race.getEvent()); - raceSubscriber = subscriberFactory.createRaceSubscriber(race); - } else { - eventSubscriber = subscriberFactory.createEventSubscriber(race.getEvent(), liveUri, storedUri); - raceSubscriber = subscriberFactory.createRaceSubscriber(race, liveUri, storedUri); - } - assertNotNull(race); - // Initialize data controller using live and stored data sources - if (storedUri != null && storedUri.toString().startsWith("file:")) { - try { - URI oldStoredUri = storedUri; - storedUri = new URI(storedUri.toString().replaceFirst("file:/([^/])", "file:////$1")); - logger.info("Replaced storedUri "+oldStoredUri+" by "+storedUri); - } catch (URISyntaxException e) { - e.printStackTrace(); + try { + final IRace race = ModelLocator.getEventFactory().createRace(new URI(paramUrl.toString()), (int) /* timeout in milliseconds */ Duration.ONE_MINUTE.asMillis()); + this.race = race; + ISubscriberFactory subscriberFactory = SubscriptionLocator.getSusbcriberFactory(); + if (storedUri == null) { + eventSubscriber = subscriberFactory.createEventSubscriber(race.getEvent()); + raceSubscriber = subscriberFactory.createRaceSubscriber(race); + } else { + eventSubscriber = subscriberFactory.createEventSubscriber(race.getEvent(), liveUri, storedUri); + raceSubscriber = subscriberFactory.createRaceSubscriber(race, liveUri, storedUri); } + assertNotNull(race); + // Initialize data controller using live and stored data sources + if (storedUri != null && storedUri.toString().startsWith("file:")) { + try { + URI oldStoredUri = storedUri; + storedUri = new URI(storedUri.toString().replaceFirst("file:/([^/])", "file:////$1")); + logger.info("Replaced storedUri "+oldStoredUri+" by "+storedUri); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + } catch (TimeOutException te) { + throw new RuntimeException(te); } // test cases need to start the thread calling addListenersForStoredDataAndStartController // after adding their listeners diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DistanceCacheInvalidationAfterLoadingFinishedTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DistanceCacheInvalidationAfterLoadingFinishedTest.java index 290a02d13cc..a9f0cdd75a0 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DistanceCacheInvalidationAfterLoadingFinishedTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DistanceCacheInvalidationAfterLoadingFinishedTest.java @@ -57,6 +57,6 @@ public class DistanceCacheInvalidationAfterLoadingFinishedTest extends TrackBase final Distance distance = speed.travel(Duration.ONE_SECOND); trackedRace.recordFix(competitor, new GPSFixMovingImpl(startPos.translateGreatCircle(bearing, distance), now.plus(Duration.ONE_SECOND), speed)); trackedRace.onStatusChanged(tdl, new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, /* progress */ 1.0)); - assertEquals(distance.getMeters(), trackedRace.getDistanceTraveled(competitor, now.plus(Duration.ONE_SECOND.times(2))).getMeters(), 0.000001); // ask 1s after the second fix + assertEquals(distance.getMeters(), trackedRace.getDistanceTraveled(competitor, now.plus(Duration.ONE_SECOND.times(2))).getMeters(), 0.01); // ask 1s after the second fix } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java index 5bcdb5ecfd1..e774019e597 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java @@ -61,6 +61,7 @@ import com.sap.sailing.domain.leaderboard.impl.HighPoint; import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOverall; import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10LastBreaksTie; import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10Or8AndLastBreaksTie; +import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets12Or8AndLastBreaksTie2017; import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; import com.sap.sailing.domain.leaderboard.impl.LowPoint; import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl; @@ -1454,6 +1455,44 @@ public class LeaderboardScoringAndRankingTest extends LeaderboardScoringAndRanki assertEquals(new Double(1), leaderboardHighPointESSOverall.getNetPoints(competitors[14], later)); assertEquals(new Double(1), leaderboardHighPointESSOverall.getNetPoints(competitors[15], later)); } + + @Test + public void testESS2017WithCompetitorsBeingDSQScoringTwoLessThanLastCompetingCompetitor() throws NoWindException { + Competitor[] competitors = createCompetitors(8).toArray(new Competitor[0]); + TimePoint now = MillisecondsTimePoint.now(); + TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000); + FlexibleLeaderboard leaderboardHighPoint12LastBreaksTie2017 = new FlexibleLeaderboardImpl("Test ESS Highpoint", + new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]), + new HighPointFirstGets12Or8AndLastBreaksTie2017(), null); + RaceColumn raceColumn = leaderboardHighPoint12LastBreaksTie2017 + .addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(competitors)), "R1", /* medalRace */ + false); + // test basic scores with best getting 12 and worst getting 5 in a 12 point scheme + assertTrue(leaderboardHighPoint12LastBreaksTie2017.getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false).compare( + leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later), + leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[3], later)) < 0); // c0 better than c3 + assertEquals(8, leaderboardHighPoint12LastBreaksTie2017.getCompetitorsFromBestToWorst(later).size()); + assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later)); + assertEquals(new Double(5), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[7], later)); + // now let's assume that the first competitor is DSQ so it gets 4 points + leaderboardHighPoint12LastBreaksTie2017.getScoreCorrection().setMaxPointsReason(competitors[0], raceColumn, MaxPointsReason.DSQ); + assertEquals(8, leaderboardHighPoint12LastBreaksTie2017.getCompetitorsFromBestToWorst(later).size()); + assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[1], later)); + assertEquals(new Double(4), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later)); + assertEquals(new Double(6), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[7], later)); + leaderboardHighPoint12LastBreaksTie2017.getScoreCorrection().setMaxPointsReason(competitors[0], raceColumn, MaxPointsReason.NONE); + assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later)); + assertEquals(new Double(5), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[7], later)); + leaderboardHighPoint12LastBreaksTie2017.getScoreCorrection().setMaxPointsReason(competitors[0], raceColumn, MaxPointsReason.DNS); + assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[1], later)); + assertEquals(new Double(5), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later)); + assertEquals(new Double(6), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[7], later)); + // two competitors not started leading to tie + leaderboardHighPoint12LastBreaksTie2017.getScoreCorrection().setMaxPointsReason(competitors[1], raceColumn, MaxPointsReason.DNS); + assertEquals(new Double(12), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[2], later)); + assertEquals(new Double(6), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[1], later)); + assertEquals(new Double(6), leaderboardHighPoint12LastBreaksTie2017.getNetPoints(competitors[0], later)); + } @Test public void testOverallLeaderboardWithESSHighPointScoring() throws NoWindException { @@ -1538,6 +1577,7 @@ public class LeaderboardScoringAndRankingTest extends LeaderboardScoringAndRanki assertEquals(c[0], rankedCompetitors.get(0)); assertEquals(c[2], rankedCompetitors.get(1)); } + @Test public void testHighPointScoringEightWithInterpolationWhenFleetNotComplete() throws NoWindException { int competitorsCount = 21; diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LineAnalysisTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LineAnalysisTest.java index ce9baf13dfb..5dc92520644 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LineAnalysisTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LineAnalysisTest.java @@ -74,7 +74,7 @@ public class LineAnalysisTest extends TrackBasedTest { final Distance distanceBehindLine = new MeterDistance(10); final Position behindMiddleOfLine = lineMiddle.translateGreatCircle(awayFromCourseSideOrthogonalToLine, distanceBehindLine); trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(behindMiddleOfLine, now, new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)))); - assertEquals(distanceBehindLine.getMeters(), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.000001); + assertEquals(distanceBehindLine.getMeters(), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.01); } @Test @@ -90,7 +90,7 @@ public class LineAnalysisTest extends TrackBasedTest { final Position behindOutsideOfLine = outsideOfLine.translateGreatCircle(awayFromCourseSideOrthogonalToLine, distanceBehindLine); trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(behindOutsideOfLine, now, new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)))); // the distance is that of the hypotenuse formed by the two cathesuses of 10m and 30m length, respectively: - assertEquals(Math.sqrt(10.*10.+30.*30.), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.001); + assertEquals(Math.sqrt(10.*10.+30.*30.), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.01); } private Mark getMark(String name) { diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java index 6d0ced1c310..2386c1ebf30 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java @@ -96,7 +96,7 @@ public class MultipleClassesInRegattaTest { /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, domainFactory, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY, - /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ true, /* preferReplayIfAvailable */ false); + /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ true, /* preferReplayIfAvailable */ false, /* timeoutInMillis */ -1); } @After diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/NonCompetingCompetitorTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/NonCompetingCompetitorTest.java new file mode 100755 index 00000000000..8a7759ea7d2 --- /dev/null +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/NonCompetingCompetitorTest.java @@ -0,0 +1,51 @@ +package com.sap.sailing.domain.test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.text.ParseException; + +import org.junit.Before; +import org.junit.Test; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.common.NoWindException; +import com.sap.sailing.domain.tractracadapter.ReceiverType; +import com.tractrac.model.lib.api.event.CreateModelException; +import com.tractrac.subscription.lib.api.SubscriberInitializationException; + +public class NonCompetingCompetitorTest extends AbstractManeuverDetectionTestCase { + public NonCompetingCompetitorTest() throws MalformedURLException, URISyntaxException { + super(); + } + + @Override + protected String getExpectedEventName() { + return "ESS ST. Petersburg 2016"; + } + + + @Before + public void setUp() throws URISyntaxException, IOException, InterruptedException, ParseException, SubscriberInitializationException, CreateModelException { + super.setUp(); + super.setUp( + new URL("http://dev.tractrac.com/events/event_20160222_ESSSTPeter_1473057208/clientparams.php?event=event_20160222_ESSSTPeter_1473057208&race=5a265e70-519a-0134-dd23-10b11c4ed8fd&random=296858907"), + /* liveUri */null, /* storedUri */null, new ReceiverType[] { ReceiverType.MARKPASSINGS, + ReceiverType.MARKPOSITIONS, ReceiverType.RACECOURSE, ReceiverType.RAWPOSITIONS }); + } + + /** + * Asserts that the "Ump..." competitors are considered non-competing and therefore don't show up + */ + @Test + public void testNoNonCompetingCompetitors() throws ParseException, NoWindException { + for (final Competitor competitor : getTrackedRace().getRace().getCompetitors()) { + assertFalse(competitor.getName().startsWith("Ump")); + assertSame(getDomainFactory().getOrCreateBoatClass("GC32"), competitor.getBoat().getBoatClass()); + } + } +} diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionAssert.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionAssert.java new file mode 100755 index 00000000000..b88c1a4742a --- /dev/null +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionAssert.java @@ -0,0 +1,77 @@ +package com.sap.sailing.domain.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.Set; + +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.Speed; +import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sailing.domain.common.Wind; +import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sailing.domain.common.tracking.GPSFixMoving; + +/** + * Contains equality assertions for "compact" fixes, allowing for deltas to be specified, assuming + * that the "compact" version of a fix may vary slightly from its original. + * + * @author Axel Uhl (d043530) + * + */ +public class PositionAssert { + public static void assertPositionEquals(Position p1, Position p2, double degreeDelta) { + assertEquals(p1.getLatDeg(), p2.getLatDeg(), degreeDelta); + assertEquals(p1.getLngDeg(), p2.getLngDeg(), degreeDelta); + } + + public static void assertGPSFixEquals(GPSFixMoving f1, GPSFixMoving f2, double positionDegreeDelta, double bearingDegreeDelta, double knotDelta) { + assertGPSFixEquals((GPSFix) f1, (GPSFix) f2, positionDegreeDelta); + assertSpeedEquals(f1.getSpeed(), f2.getSpeed(), bearingDegreeDelta, knotDelta); + } + + public static void assertBearingEquals(Bearing b1, Bearing b2, double bearingDegreeDelta) { + assertEquals(b1.getDegrees(), b2.getDegrees(), bearingDegreeDelta); + } + + public static void assertGPSFixEquals(GPSFix f1, GPSFix f2, double positionDegreeDelta) { + assertPositionEquals(f1.getPosition(), f2.getPosition(), positionDegreeDelta); + assertEquals(f1.getTimePoint(), f2.getTimePoint()); + } + + public static void assertWindEquals(Wind w1, Wind w2, double posDegDelta, double bearingDegreeDelta, double knotSpeedDelta) { + assertEquals(w1.getTimePoint(), w2.getTimePoint()); + assertPositionEquals(w1.getPosition(), w2.getPosition(), posDegDelta); + assertBearingEquals(w1.getBearing(), w2.getBearing(), bearingDegreeDelta); + assertSpeedEquals(w1, w2, bearingDegreeDelta, knotSpeedDelta); + } + + public static void assertSpeedEquals(Speed s1, Speed s2, double knotSpeedDelta) { + assertEquals(s1.getKnots(), s2.getKnots(), knotSpeedDelta); + } + + public static void assertSpeedEquals(SpeedWithBearing s1, SpeedWithBearing s2, double bearingDegreeDelta, double knotSpeedDelta) { + assertBearingEquals(s1.getBearing(), s2.getBearing(), bearingDegreeDelta); + assertSpeedEquals((Speed) s1, (Speed) s2, knotSpeedDelta); + } + + public static void assertWindEquals(Set expectedWinds, Set actualWinds, double posDegDelta, + double bearingDegreeDelta, double knotSpeedDelta) { + for (final Wind expectedWind : expectedWinds) { + boolean found = false; + for (final Wind actualWind : actualWinds) { + try { + assertWindEquals(expectedWind, actualWind, posDegDelta, bearingDegreeDelta, knotSpeedDelta); + found = true; + break; + } catch (AssertionError e) { + // not equals + } + } + if (!found) { + fail("Expected to find "+expectedWind+" in "+actualWinds+" but didn't"); + } + } + } +} diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionTest.java index 1d76669219e..5c7b653a13e 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionTest.java @@ -16,8 +16,11 @@ import com.sap.sailing.domain.common.impl.DegreePosition; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.common.impl.NauticalMileDistance; -import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl; -import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl; +import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl; +import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException; +import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; public class PositionTest { @@ -32,20 +35,40 @@ public class PositionTest { @Test public void testEqualityBetweenCompactAndVerbosePosition() { Position p1 = new DegreePosition(49.2, 008.3); - CompactGPSFixImpl compactFix = new CompactGPSFixImpl(p1, MillisecondsTimePoint.now()); + VeryCompactGPSFixImpl compactFix = new VeryCompactGPSFixImpl(p1, MillisecondsTimePoint.now()); assertNotSame(p1, compactFix.getPosition()); - assertEquals(p1, compactFix.getPosition()); + PositionAssert.assertPositionEquals(p1, compactFix.getPosition(), 0.000001); } @Test - public void testEqualityBetweenCompactAndVerboseSpeedWithBearing() { + public void testCompactFixRange() { + final TimePoint now = MillisecondsTimePoint.now(); + assertCompactFixHasEqualLatLng(now, 0., 0.); + assertCompactFixHasEqualLatLng(now, 90., 0.); + assertCompactFixHasEqualLatLng(now, -90., 0.); + assertCompactFixHasEqualLatLng(now, 0., 180.); + assertCompactFixHasEqualLatLng(now, 0., -180.); + assertCompactFixHasEqualLatLng(now, 45., 45.); + assertCompactFixHasEqualLatLng(now, 0., -45.); + assertCompactFixHasEqualLatLng(now, -45., 45.); + assertCompactFixHasEqualLatLng(now, 0., 45.); + } + + private void assertCompactFixHasEqualLatLng(final TimePoint now, final double latDeg, final double lngDeg) { + GPSFix fix = new VeryCompactGPSFixImpl(new DegreePosition(latDeg, lngDeg), now); + assertEquals(latDeg, fix.getPosition().getLatDeg(), 0.0000001); + assertEquals(lngDeg, fix.getPosition().getLngDeg(), 0.0000001); + } + + @Test + public void testEqualityBetweenCompactAndVerboseSpeedWithBearing() throws CompactionNotPossibleException { Position p1 = new DegreePosition(49.2, 008.3); SpeedWithBearing swb = new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)); - CompactGPSFixMovingImpl compactFix = new CompactGPSFixMovingImpl(p1, MillisecondsTimePoint.now(), swb); + VeryCompactGPSFixMovingImpl compactFix = new VeryCompactGPSFixMovingImpl(p1, MillisecondsTimePoint.now(), swb); assertNotSame(p1, compactFix.getPosition()); - assertEquals(p1, compactFix.getPosition()); + PositionAssert.assertPositionEquals(p1, compactFix.getPosition(), 0.000001); assertNotSame(swb, compactFix.getSpeed()); - assertEquals(swb, compactFix.getSpeed()); + PositionAssert.assertSpeedEquals(swb, compactFix.getSpeed(), /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1); } @Test diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java index d77f4c76acb..1014e9c2ea8 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java @@ -338,7 +338,7 @@ public class ReachingLegTest extends TrackBasedTest { Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE); assertEquals(0., schomaekersDistanceToLeader.getMeters(), 0.00001); // distance to leading Schomaeker expected to be the entire upwind distance plus the offset distance plus half the downwind - assertEquals(distanceOfReachingLeg.getMeters()+windwardDistanceOfUpwindLeg.getMeters()*1.5, plattnersDistanceToLeader.getMeters(), 0.001); + assertEquals(distanceOfReachingLeg.getMeters()+windwardDistanceOfUpwindLeg.getMeters()*1.5, plattnersDistanceToLeader.getMeters(), 0.01); } @Test @@ -373,9 +373,9 @@ public class ReachingLegTest extends TrackBasedTest { .getEstimatedPosition(timePointToConsider, /* extrapolate */false) .getDistance( getTrackedRace().getTrack(plattner).getEstimatedPosition(timePointToConsider, /* extrapolate */ - false)).getMeters(), 0.00001); + false)).getMeters(), 0.01); // however, projected onto the leg their distance should be 0 Distance plattnersDistanceToLeader = getTrackedRace().getWindwardDistanceToCompetitorFarthestAhead(plattner, timePointToConsider, WindPositionMode.LEG_MIDDLE); - assertEquals(0., plattnersDistanceToLeader.getMeters(), 0.00001); + assertEquals(0., plattnersDistanceToLeader.getMeters(), 0.01); } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java index c8a621c5707..911ed8fe8a8 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java @@ -141,7 +141,7 @@ public class StarbordSideOfStartLineRecognitionTest { MockedTrackedRaceImpl trackedRace = createTrackedRaceWithMarkPositions(startPortPosition, startStarboardPosition, windwardPosition); Position p = trackedRace.getOrCreateTrack(trackedRace.getStartLine(now).getStarboardMarkWhileApproachingLine()). getEstimatedPosition(now, /* extrapolate */ false); - assertEquals(startStarboardPosition, p); + PositionAssert.assertPositionEquals(startStarboardPosition, p, 0.0000001); } @Test diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackTest.java index 2f5c7bf7de5..ce1092fcf4e 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackTest.java @@ -43,7 +43,8 @@ import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.common.impl.MeterPerSecondSpeedWithDegreeBearingImpl; import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.common.tracking.GPSFixMoving; -import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl; +import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException; import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; @@ -63,6 +64,7 @@ import com.sap.sse.common.Util.Pair; import com.sap.sse.common.impl.MillisecondsTimePoint; public class TrackTest { + private static final int MILLIS_BETWEEN_FIXES = 3000000; private DynamicGPSFixTrack track; private GPSFixMovingImpl gpsFix1; private GPSFixMovingImpl gpsFix2; @@ -75,7 +77,7 @@ public class TrackTest { track = new DynamicGPSFixMovingTrackImpl(new BoatImpl("MyFirstBoat", new BoatClassImpl("505", /* typicallyStartsUpwind */ true), null), /* millisecondsOverWhichToAverage */5000, /* no smoothening */null); TimePoint now1 = MillisecondsTimePoint.now(); - TimePoint now2 = addMillisToTimepoint(now1, 3); + TimePoint now2 = addMillisToTimepoint(now1, MILLIS_BETWEEN_FIXES); DegreePosition position1 = new DegreePosition(1, 2); DegreePosition position2 = new DegreePosition(1, 3); gpsFix1 = new GPSFixMovingImpl( @@ -84,19 +86,19 @@ public class TrackTest { new DegreeBearingImpl(90))); gpsFix2 = new GPSFixMovingImpl(position2, now2, new KnotSpeedWithBearingImpl(position1.getDistance(position2) .inTime(now2.asMillis() - gpsFix1.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(90))); - TimePoint now3 = addMillisToTimepoint(now2, 3); + TimePoint now3 = addMillisToTimepoint(now2, MILLIS_BETWEEN_FIXES); Position position3 = new DegreePosition(1, 4); gpsFix3 = new GPSFixMovingImpl( position3, now3, new KnotSpeedWithBearingImpl(position2.getDistance(position3) .inTime(now3.asMillis() - gpsFix2.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(0))); - TimePoint now4 = addMillisToTimepoint(now3, 3); + TimePoint now4 = addMillisToTimepoint(now3, MILLIS_BETWEEN_FIXES); Position position4 = new DegreePosition(3, 4); gpsFix4 = new GPSFixMovingImpl( position4, now4, new KnotSpeedWithBearingImpl(position3.getDistance(position4) .inTime(now4.asMillis() - gpsFix3.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(0))); - TimePoint now5 = addMillisToTimepoint(now4, 3); + TimePoint now5 = addMillisToTimepoint(now4, MILLIS_BETWEEN_FIXES); Position position5 = new DegreePosition(5, 4); gpsFix5 = new GPSFixMovingImpl(position5, now5, new KnotSpeedWithBearingImpl(position4.getDistance(position5) .inTime(now5.asMillis() - gpsFix4.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(0))); @@ -106,6 +108,7 @@ public class TrackTest { track.addGPSFix(gpsFix4); track.addGPSFix(gpsFix5); } + /** * Tests for a incorrect method of estimating Positions */ @@ -128,7 +131,6 @@ public class TrackTest { assertEquals(45, track.getEstimatedPosition(t1.plus(15), true).getLatDeg(), 0.00000001); assertEquals(60, track.getEstimatedPosition(t1.plus(20), true).getLatDeg(), 0.00000001); assertEquals(90, track.getEstimatedPosition(t1.plus(30), true).getLatDeg(), 0.00000001); - } finally { track.unlockAfterRead(); } @@ -221,7 +223,7 @@ public class TrackTest { now = nextNow; } assertEquals(speed.travel(start, now.minus(NUMBER_OF_FIXES_AT_SAME_POSITION * 1000)).getMeters(), - track.getDistanceTraveled(start, now).getMeters(), 0.00000001); + track.getDistanceTraveled(start, now).getMeters(), 0.01); } private void addFixesWithSamePositionButProgressingTime(DynamicGPSFixTrack track, @@ -320,7 +322,7 @@ public class TrackTest { cacheBarrier.await(20, TimeUnit.SECONDS); cacheDone.await(20, TimeUnit.SECONDS); testDone.await(); - assertEquals(2., maxSpeed[0], 0.001); + assertEquals(2., maxSpeed[0], 0.1); } @Test @@ -366,12 +368,12 @@ public class TrackTest { 1, new DegreeBearingImpl(123))); track.addGPSFix(fix3); assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(7200000)). - getB().getKnots(), 0.001); // produces a cache entry that ends + getB().getKnots(), 0.01); // produces a cache entry that ends GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(10800000), new KnotSpeedWithBearingImpl( 1, new DegreeBearingImpl(123))); track.addGPSFix(fix4); assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)). - getB().getKnots(), 0.001); + getB().getKnots(), 0.01); } @Test @@ -383,7 +385,7 @@ public class TrackTest { 2, new DegreeBearingImpl(123))); track.addGPSFix(fast); assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)). - getB().getKnots(), 0.001); + getB().getKnots(), 0.01); track.addGPSFix(slow); track.lockForRead(); try { @@ -392,7 +394,7 @@ public class TrackTest { track.unlockAfterRead(); } assertEquals(1., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)). - getB().getKnots(), 0.001); + getB().getKnots(), 0.01); } @Test @@ -405,7 +407,7 @@ public class TrackTest { 2, new DegreeBearingImpl(123))); track.addGPSFix(fix2); assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(7200000)). - getB().getKnots(), 0.001); // produces a cache entry that ends + getB().getKnots(), 0.01); // produces a cache entry that ends GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(7200000), new KnotSpeedWithBearingImpl( 1, new DegreeBearingImpl(123))); track.addGPSFix(fix3); @@ -413,7 +415,7 @@ public class TrackTest { 1, new DegreeBearingImpl(123))); track.addGPSFix(fix4); assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)). - getB().getKnots(), 0.001); + getB().getKnots(), 0.01); } /** @@ -462,7 +464,7 @@ public class TrackTest { track.addGPSFix(f2); track.addGPSFix(f3); SpeedWithBearing average = track.getEstimatedSpeed(t2); - assertEquals(0, average.getBearing().getDegrees(), 0.00001); + PositionAssert.assertBearingEquals(new DegreeBearingImpl(0), average.getBearing(), 0.1); } @Test @@ -477,7 +479,7 @@ public class TrackTest { track.addGPSFix(f1); track.addGPSFix(f2); track.addGPSFix(f3); - assertEquals(f2, track.getFirstFixAtOrAfter(f2.getTimePoint())); // expect the fix to still be valid, but only its provided speed shall be ignored + PositionAssert.assertGPSFixEquals(f2, track.getFirstFixAtOrAfter(f2.getTimePoint()), /* pos deg delta */ 0.00001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01); // expect the fix to still be valid, but only its provided speed shall be ignored } @Test @@ -492,7 +494,7 @@ public class TrackTest { track.addGPSFix(f1); track.addGPSFix(f2); track.addGPSFix(f3); - assertEquals(f3, track.getFirstFixAtOrAfter(f2.getTimePoint())); // expect the f2 fix to be invalid + PositionAssert.assertGPSFixEquals(f3, track.getFirstFixAtOrAfter(f2.getTimePoint()), /* pos deg delta */ 0.00001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01); // expect the fix to still be valid, but only its provided speed shall be ignored } @Test @@ -508,7 +510,7 @@ public class TrackTest { track.addGPSFix(f2); track.addGPSFix(f3); // expect the f2 fix to be invalid because provided speed is too different - assertEquals(0, f3.getPosition().getDistance(track.getFirstFixAtOrAfter(f2.getTimePoint()).getPosition()).getMeters(), 0.001); + assertEquals(0, f3.getPosition().getDistance(track.getFirstFixAtOrAfter(f2.getTimePoint()).getPosition()).getMeters(), 0.01); } @Test @@ -523,9 +525,9 @@ public class TrackTest { track.addGPSFix(f1); track.addGPSFix(f2); track.addGPSFix(f3); - assertEquals(f2, track.getFirstFixAtOrAfter(f2.getTimePoint())); // expect the fix to still be valid, but only its provided speed shall be ignored + PositionAssert.assertGPSFixEquals(f2, track.getFirstFixAtOrAfter(f2.getTimePoint()), /* pos deg delta */ 0.00001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01); // expect the fix to still be valid, but only its provided speed shall be ignored SpeedWithBearing average = track.getEstimatedSpeed(t2); - assertEquals(1, average.getKnots(), 0.001); + assertEquals(1, average.getKnots(), 0.01); } @Test @@ -541,7 +543,7 @@ public class TrackTest { track.addGPSFix(f2); track.addGPSFix(f3); SpeedWithBearing average = track.getRawEstimatedSpeed(t2); - assertEquals(0, average.getBearing().getDegrees(), 0.00001); + PositionAssert.assertBearingEquals(new DegreeBearingImpl(0), average.getBearing(), /* deg delta */ 0.1); } /** @@ -560,14 +562,14 @@ public class TrackTest { Iterator subsetIter = subset.iterator(); // start iteration GPSFixMoving firstOfSubset = subsetIter.next(); - assertEquals(gpsFix2, firstOfSubset); + PositionAssert.assertGPSFixEquals(gpsFix2, firstOfSubset, /* pos deg delta */ 0.00001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01); // now add a fix: TimePoint now6 = addMillisToTimepoint(gpsFix5.getTimePoint(), 3); track.addGPSFix(new GPSFixMovingImpl( new DegreePosition(6, 5), now6, new KnotSpeedWithBearingImpl(2, new DegreeBearingImpl(0)))); try { GPSFixMoving secondOfSubset = subsetIter.next(); - assertEquals(gpsFix3, secondOfSubset); + PositionAssert.assertGPSFixEquals(gpsFix3, secondOfSubset, /* pos deg delta */ 0.000001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01); fail("adding a fix interferes with iteration over subSet of track's fixes"); } catch (ConcurrentModificationException e) { // this is what we expected @@ -675,7 +677,7 @@ public class TrackTest { TimePoint afterTimePoint = new MillisecondsTimePoint(millis + (millis-lastMillis)); Position extrapolatedPosition = track.getEstimatedPosition(afterTimePoint, true); assertEquals(0.5, fix.getPosition().getDistance(extrapolatedPosition).getMeters() - / lastFix.getPosition().getDistance(extrapolatedPosition).getMeters(), 0.00001); + / lastFix.getPosition().getDistance(extrapolatedPosition).getMeters(), 0.01); } @Test @@ -792,7 +794,7 @@ public class TrackTest { bearing = new DegreeBearingImpl(bearing.getDegrees() + 1); } invalidationCalls.clear(); - assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.01); + assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.02); final com.sap.sse.common.Util.Pair> fullIntervalCacheEntry = distanceCache.getEarliestFromAndDistanceAtOrAfterFrom(now, start); assertNotNull(fullIntervalCacheEntry); // no more entry for "to"-value start in cache assertEquals(start, fullIntervalCacheEntry.getA()); @@ -808,7 +810,7 @@ public class TrackTest { invalidationCalls.clear(); final TimePoint timePointOfLastOriginalFix = track.getLastRawFix().getTimePoint(); assertEquals(speed.getMetersPerSecond() * (steps - 1), - track.getDistanceTraveled(now, timePointOfLastOriginalFix).getMeters(), 0.01); + track.getDistanceTraveled(now, timePointOfLastOriginalFix).getMeters(), 0.02); final com.sap.sse.common.Util.Pair> newFullIntervalCacheEntry = distanceCache .getEarliestFromAndDistanceAtOrAfterFrom(now, timePointOfLastOriginalFix); assertNotNull(newFullIntervalCacheEntry); // no more entry for "to"-value start in cache @@ -861,7 +863,7 @@ public class TrackTest { track.unlockAfterRead(); } GPSFix polishedLastFix2 = track.getLastFixBefore(new MillisecondsTimePoint(Long.MAX_VALUE)); // get the last smoothened fix... - assertEquals(fix, polishedLastFix2); + PositionAssert.assertGPSFixEquals(fix, polishedLastFix2, /* pos deg delta */ 0.000001); assertEquals(speed.getMetersPerSecond()*steps, track.getDistanceTraveled(now, start).getMeters(), 0.01); } @@ -1003,7 +1005,7 @@ public class TrackTest { final TimePoint stripTo = start.minus(2*timeBetweenFixesInMillis); assertEquals(speed.getMetersPerSecond()*(steps-3), track.getDistanceTraveled(stripFrom, stripTo).getMeters(), 0.01); - assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.01); + assertEquals(speed.getMetersPerSecond()*(steps-1), track.getDistanceTraveled(now, start).getMeters(), 0.02); assertTrue(invalidationCalls.isEmpty()); // expect a cache entry exactly for the strip's boundaries com.sap.sse.common.Util.Pair> stripCacheEntry = distanceCache.getEarliestFromAndDistanceAtOrAfterFrom(stripFrom, stripTo); @@ -1054,8 +1056,7 @@ public class TrackTest { assertEquals(gpsFix2.getPosition().getLatDeg(), estimatedPosNew.getLatDeg(), 0.5); assertEquals(gpsFix2.getPosition().getLngDeg(), estimatedPosNew.getLngDeg(), 0.5); SpeedWithBearing estimatedSpeedNew = track.getEstimatedSpeed(normalFixesTime); - assertEquals(estimatedSpeed.getKnots(), estimatedSpeedNew.getKnots(), 0.001); - assertEquals(estimatedSpeed.getBearing().getDegrees(), estimatedSpeedNew.getBearing().getDegrees(), 0.001); + PositionAssert.assertSpeedEquals(estimatedSpeed, estimatedSpeedNew, /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1); } @Test @@ -1262,21 +1263,21 @@ public class TrackTest { @Test public void testFrequency() { - assertEquals(3, track.getAverageIntervalBetweenFixes().asMillis()); - assertEquals(3, track.getAverageIntervalBetweenRawFixes().asMillis()); + assertEquals(MILLIS_BETWEEN_FIXES, track.getAverageIntervalBetweenFixes().asMillis()); + assertEquals(MILLIS_BETWEEN_FIXES, track.getAverageIntervalBetweenRawFixes().asMillis()); } @Test - public void testEstimatedSpeedCaching() { + public void testEstimatedSpeedCaching() throws CompactionNotPossibleException { GPSFixMoving originalFix = new GPSFixMovingImpl(new DegreePosition(12, 34), MillisecondsTimePoint.now(), new KnotSpeedWithBearingImpl(9, new DegreeBearingImpl(123))); - GPSFixMoving fix = new CompactGPSFixMovingImpl(originalFix); + GPSFixMoving fix = new VeryCompactGPSFixMovingImpl(originalFix); assertFalse(fix.isEstimatedSpeedCached()); final KnotSpeedWithBearingImpl estimatedSpeed = new KnotSpeedWithBearingImpl(9.1, new DegreeBearingImpl(124)); fix.cacheEstimatedSpeed(estimatedSpeed); assertTrue(fix.isEstimatedSpeedCached()); SpeedWithBearing cachedEstimatedSpeed = fix.getCachedEstimatedSpeed(); - assertEquals(estimatedSpeed, cachedEstimatedSpeed); + PositionAssert.assertSpeedEquals(estimatedSpeed, cachedEstimatedSpeed, /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1); fix.invalidateEstimatedSpeedCache(); assertFalse(fix.isEstimatedSpeedCached()); } @@ -1287,8 +1288,9 @@ public class TrackTest { assertFalse(compactFix3.isEstimatedSpeedCached()); SpeedWithBearing fix3EstimatedSpeed = track.getEstimatedSpeed(gpsFix3.getTimePoint()); assertTrue(compactFix3.isEstimatedSpeedCached()); - assertEquals(fix3EstimatedSpeed, compactFix3.getCachedEstimatedSpeed()); - assertEquals(fix3EstimatedSpeed, track.getEstimatedSpeed(gpsFix3.getTimePoint())); // fetch again from the cache + PositionAssert.assertSpeedEquals(fix3EstimatedSpeed, compactFix3.getCachedEstimatedSpeed(), /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1); + PositionAssert.assertSpeedEquals(fix3EstimatedSpeed, track.getEstimatedSpeed(gpsFix3.getTimePoint()), + /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1); // fetch again from the cache // assuming that all test fixes are within a few milliseconds and the averaging interval is much larger than that, // adding a single fix in the middle should invalidate the cache track.add(new GPSFixMovingImpl(gpsFix3.getPosition(), gpsFix3.getTimePoint().plus(1), gpsFix3.getSpeed())); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java index dbc225179ca..70ee5c4ea27 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java @@ -68,7 +68,9 @@ public class UnicodeCharactersInCompetitorNamesTest { /* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, domainFactory, - "tracTest", "tracTest", "", "", /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ true, /* preferReplayIfAvailable */ false), RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS); + "tracTest", "tracTest", "", "", /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ true, + /* preferReplayIfAvailable */ false, /* timeoutInMillis */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS), + RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS); Iterable competitors = fourtyninerYellow_2.getRaceHandle().getRace().getCompetitors(); for (Competitor competitor : competitors) { diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindEstimationOnConstructedTracksTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindEstimationOnConstructedTracksTest.java index 38799401bfc..f0f7d2a0ad1 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindEstimationOnConstructedTracksTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindEstimationOnConstructedTracksTest.java @@ -186,9 +186,9 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest }; Wind estimatedWindDirection = track.getAveragedWind(/* position */ null, checkTime); assertNotNull(estimatedWindDirection); - assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001); + assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1); assertFalse(cachedFixes.isEmpty()); - assertEquals(185., cachedFixes.values().iterator().next().getObject().getBearing().getDegrees(), 0.00000001); + assertEquals(185., cachedFixes.values().iterator().next().getObject().getBearing().getDegrees(), 0.1); // now invert leg's type by moving the top mark along the wind from the leeward gate: Iterator waypointsIter = getTrackedRace().getRace().getCourse().getWaypoints().iterator(); Waypoint leewardMark = waypointsIter.next(); @@ -202,7 +202,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest assertEquals(LegType.DOWNWIND, firstLeg.getLegType(fixTime)); Wind estimatedWindDirectionDownwind = track.getAveragedWind(/* position */ null, checkTime); assertNotNull(estimatedWindDirectionDownwind); - assertEquals(185., estimatedWindDirectionDownwind.getBearing().getDegrees(), 0.00000001); + assertEquals(185., estimatedWindDirectionDownwind.getBearing().getDegrees(), 0.1); } @Test @@ -229,15 +229,15 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest }; Wind estimatedWindDirection = track.getAveragedWind(/* position */ null, checkTime); assertNotNull(estimatedWindDirection); - assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001); + assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1); assertFalse(cachedFixes.isEmpty()); - assertEquals(185., cachedFixes.values().iterator().next().getObject().getBearing().getDegrees(), 0.00000001); + assertEquals(185., cachedFixes.values().iterator().next().getObject().getBearing().getDegrees(), 0.1); // now clear set of cached fixes, ask again and ensure nothing is cached again: cachedFixes.clear(); Wind estimatedWindDirectionCached = track.getAveragedWind(/* position */ null, checkTime); assertTrue(cachedFixes.isEmpty()); assertNotNull(estimatedWindDirectionCached); - assertEquals(185., estimatedWindDirectionCached.getBearing().getDegrees(), 0.00000001); + assertEquals(185., estimatedWindDirectionCached.getBearing().getDegrees(), 0.1); // now add a GPS fix and make sure the cache is invalidated by adding it inside the averaging interval now = new MillisecondsTimePoint(checkTime.asMillis() + track.getMillisecondsOverWhichToAverageWind()/2); setBearingForCompetitor(competitors.get(0), now, 330); @@ -257,7 +257,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest setBearingForCompetitor(competitors.get(0), now, 320); setBearingForCompetitor(competitors.get(1), now, 50); Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(now); - assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001); + assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1); } @Test @@ -268,7 +268,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest setBearingForCompetitor(competitors.get(1), now, 50); setBearingForCompetitor(competitors.get(2), new MillisecondsTimePoint(0), 100); // this shouldn't disturb the estimation because it's too old Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(now); - assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001); + assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1); } @Test @@ -280,7 +280,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest setBearingForCompetitor(competitors.get(1), now, 50); setBearingForCompetitor(competitors.get(2), markPassingTimePoint, 100); // this shouldn't disturb the estimation because it's too old Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(now); - assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.00000001); + assertEquals(185., estimatedWindDirection.getBearing().getDegrees(), 0.1); } @Test @@ -318,7 +318,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest setBearingForCompetitor(competitors.get(2), now, 135); setBearingForCompetitor(competitors.get(3), now, 220); // on the same tack, should give no read-out Wind estimatedWindDirection = getTrackedRace().getEstimatedWindDirection(now); - assertEquals(177.5, estimatedWindDirection.getBearing().getDegrees(), 0.00000001); + assertEquals(177.5, estimatedWindDirection.getBearing().getDegrees(), 0.1); } @Test diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java index 149dbcf88b1..353c8f65431 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java @@ -43,10 +43,12 @@ import com.sap.sailing.domain.common.confidence.Weigher; import com.sap.sailing.domain.common.confidence.impl.PositionAndTimePointWeigher; import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.impl.KnotSpeedImpl; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.common.impl.WindImpl; -import com.sap.sailing.domain.common.tracking.impl.CompactWindImpl; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl; +import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException; import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager; import com.sap.sailing.domain.confidence.ConfidenceFactory; import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore; @@ -86,7 +88,7 @@ public class WindTest { track.add(wind1); track.add(wind2); Wind average = track.getAveragedWind(pos, middle); - assertEquals(0., average.getBearing().getDifferenceTo(new DegreeBearingImpl(0)).getDegrees(), 0.0001); + PositionAssert.assertBearingEquals(new DegreeBearingImpl(0), average.getBearing().getDifferenceTo(new DegreeBearingImpl(0)), 0.01); } @Test @@ -109,14 +111,14 @@ public class WindTest { for (Wind wind : track.getFixes()) { actualWind.add(wind); } - assertEquals(expectedWind, actualWind); + PositionAssert.assertWindEquals(expectedWind, actualWind, /* pos deg delta */ 0.000001, /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1); } finally { track.unlockAfterRead(); } } @Test - public void testWindEquality() { + public void testWindEquality() throws CompactionNotPossibleException { Position p1 = new DegreePosition(1, 2); Position p2 = new DegreePosition(4, 5); TimePoint t1 = MillisecondsTimePoint.now(); @@ -124,8 +126,8 @@ public class WindTest { SpeedWithBearing s1 = new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(3)); SpeedWithBearing s2 = new KnotSpeedWithBearingImpl(22, new DegreeBearingImpl(123)); Wind w1 = new WindImpl(p1, t1, s1); - Wind w2 = new CompactWindImpl(w1); - assertEquals(w1, w2); + Wind w2 = new VeryCompactWindImpl(w1); + PositionAssert.assertWindEquals(w1, w2, /* pos deg delta */ 0.000001, /* bearing deg delta */ 0.1, /* knot speed delta */ 0.1); assertEquals(w1.hashCode(), w2.hashCode()); Wind w3 = new WindImpl(p2, t2, s2); assertFalse(w1.equals(w3)); @@ -163,9 +165,9 @@ public class WindTest { track.add(wind7); // interval does bearely reach 20's burst because 0 has 0 length and 1000..30000 has 29000 length - assertEquals(20, track.getAveragedWind(pos, new MillisecondsTimePoint(1)).getKnots(), 0.00000001); + PositionAssert.assertSpeedEquals(new KnotSpeedImpl(20), track.getAveragedWind(pos, new MillisecondsTimePoint(1)), 0.02); // interval uses the two fixes to the left (0, 1000)=1000 and three to the right (2000, 10000, 30000)=28000 - assertEquals(20, track.getAveragedWind(pos, new MillisecondsTimePoint(1001)).getKnots(), 0.00000001); + PositionAssert.assertSpeedEquals(new KnotSpeedImpl(20), track.getAveragedWind(pos, new MillisecondsTimePoint(1001)), 0.02); // in the middle of the "hole", fetches (0, 1000, 2000, 10000)=10000 and (30000, 40000)=10000, so 20000ms worth of wind final double averageFor20000 = track.getAveragedWind(pos, new MillisecondsTimePoint(20000)).getKnots(); // value is hard to predict exactly because time difference-based confidences rate fixes closer to 20000ms higher than those further away @@ -183,8 +185,7 @@ public class WindTest { Wind wind = new WindImpl(pos, new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123))); track.add(wind); Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(0)); - assertEquals(10, estimate.getKnots(), 0.000000001); - assertEquals(123, estimate.getBearing().getDegrees(), 0.000000001); + PositionAssert.assertSpeedEquals(new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)), estimate, /* deg bearing delta */ 0.1, /* knot speed delta */ 0.01); } @Test @@ -195,8 +196,8 @@ public class WindTest { track.add(wind); // we only have one measurement; this should be extrapolated because it's our best guess Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(1000)); - assertEquals(10, estimate.getKnots(), 0.000000001); - assertEquals(123, estimate.getBearing().getDegrees(), 0.000000001); + PositionAssert.assertSpeedEquals(new KnotSpeedImpl(10), estimate, 0.01); + PositionAssert.assertBearingEquals(new DegreeBearingImpl(123), estimate.getBearing(), 0.01); } @Test @@ -208,8 +209,7 @@ public class WindTest { // we only have one measurement; this should be extrapolated because it's our best guess even if // the last measurement was longer ago than our smoothening interval Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(AVERAGING_INTERVAL_MILLIS+1000)); - assertEquals(10, estimate.getKnots(), 0.000000001); - assertEquals(123, estimate.getBearing().getDegrees(), 0.000000001); + PositionAssert.assertSpeedEquals(new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(123)), estimate, /* deg bearing delta */ 0.1, /* knot speed delta */ 0.01); } @Test @@ -221,8 +221,7 @@ public class WindTest { Wind wind2 = new WindImpl(pos, new MillisecondsTimePoint(1000), new KnotSpeedWithBearingImpl(20, new DegreeBearingImpl(100))); track.add(wind2); Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(500)); - assertEquals(15, estimate.getKnots(), 0.000000001); - assertEquals(100, estimate.getBearing().getDegrees(), 0.00000001); + PositionAssert.assertSpeedEquals(new KnotSpeedWithBearingImpl(15, new DegreeBearingImpl(100)), estimate, /* deg bearing delta */ 0.1, /* knot speed delta */ 0.01); } @Test @@ -234,8 +233,7 @@ public class WindTest { Wind wind2 = new WindImpl(pos, new MillisecondsTimePoint(1000), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(100))); track.add(wind2); Wind estimate = track.getAveragedWind(pos, new MillisecondsTimePoint(2000)); - assertEquals(10, estimate.getKnots(), 0.000000001); - assertEquals(105, estimate.getBearing().getDegrees(), 0.6); // some tolerance needed because of time-based confidence + PositionAssert.assertSpeedEquals(new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(105)), estimate, /* deg bearing delta, some tolerance needed because of time-based confidence */ 0.6, /* knot speed delta */ 0.01); } @Test @@ -266,7 +264,7 @@ public class WindTest { TimePoint timePoint = new MillisecondsTimePoint(df.parse("2009-07-11T17:31:38").getTime()); Wind result = track.getAveragedWind(null, timePoint); // expectation: take two from left (because they are closer than AVERAGING_INTERVAL_MILLIS apart), one from right side: - assertEquals((wind1.getKnots() + wind2.getKnots() + wind3.getKnots()) / 3, result.getKnots(), 0.000000001); + assertEquals((wind1.getKnots() + wind2.getKnots() + wind3.getKnots()) / 3, result.getKnots(), 0.01); assertEquals(80., result.getBearing().getDegrees(), 5); } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/tractrac/JorgesTracTracParallelLoadingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/tractrac/JorgesTracTracParallelLoadingTest.java index e90db1538bb..e2bb443f9f6 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/tractrac/JorgesTracTracParallelLoadingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/tractrac/JorgesTracTracParallelLoadingTest.java @@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit; import org.junit.Test; +import com.sap.sse.common.Duration; import com.tractrac.model.lib.api.ModelLocator; import com.tractrac.model.lib.api.data.IControlPassing; import com.tractrac.model.lib.api.data.IControlPassings; @@ -66,7 +67,7 @@ public class JorgesTracTracParallelLoadingTest { threads.add(new Thread(()->{ try { // Download the parameters file and load the race - IRace race = ModelLocator.getEventFactory().createRace(new URI(paramsURIs.get(index))); + IRace race = ModelLocator.getEventFactory().createRace(new URI(paramsURIs.get(index)), (int) /* timeout in milliseconds */ Duration.ONE_MINUTE.asMillis()); // Create the subscriptions SubscriptionLogger subscriptionLogger = new SubscriptionLogger(race); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/PositionInterpolationAndExtrapolationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/PositionInterpolationAndExtrapolationTest.java index 5e911820806..556210599a2 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/PositionInterpolationAndExtrapolationTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/PositionInterpolationAndExtrapolationTest.java @@ -1,10 +1,9 @@ package com.sap.sailing.domain.tracking.impl; -import static org.junit.Assert.assertEquals; - import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.impl.DegreePosition; import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sailing.domain.test.PositionAssert; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; @@ -22,7 +21,7 @@ public abstract class PositionInterpolationAndExtrapolationTest getTrack() { diff --git a/java/com.sap.sailing.domain.tractracadapter.persistence/src/com/sap/sailing/domain/tractracadapter/persistence/impl/TracTracConnectivityParamsHandler.java b/java/com.sap.sailing.domain.tractracadapter.persistence/src/com/sap/sailing/domain/tractracadapter/persistence/impl/TracTracConnectivityParamsHandler.java index 32d2823ef97..0c397e2e42c 100644 --- a/java/com.sap.sailing.domain.tractracadapter.persistence/src/com/sap/sailing/domain/tractracadapter/persistence/impl/TracTracConnectivityParamsHandler.java +++ b/java/com.sap.sailing.domain.tractracadapter.persistence/src/com/sap/sailing/domain/tractracadapter/persistence/impl/TracTracConnectivityParamsHandler.java @@ -7,6 +7,7 @@ import java.util.Map; import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.regattalog.RegattaLogStore; +import com.sap.sailing.domain.tracking.RaceTracker; import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters; import com.sap.sailing.domain.tracking.impl.AbstractRaceTrackingConnectivityParametersHandler; import com.sap.sailing.domain.tractracadapter.DomainFactory; @@ -88,7 +89,8 @@ public class TracTracConnectivityParamsHandler extends AbstractRaceTrackingConne map.get(TRAC_TRAC_PASSWORD)==null?null:map.get(TRAC_TRAC_PASSWORD).toString(), map.get(RACE_STATUS)==null?null:map.get(RACE_STATUS).toString(), map.get(RACE_VISIBILITY)==null?null:map.get(RACE_VISIBILITY).toString(), isTrackWind(map), - isCorrectWindDirectionByMagneticDeclination(map), /* preferReplayIfAvailable */ true); + isCorrectWindDirectionByMagneticDeclination(map), /* preferReplayIfAvailable */ true, + /* default timeout for obtaining IRace object from params URL */ (int) RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS); } @Override diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java index 070882e1277..ebe80826647 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java @@ -11,6 +11,7 @@ import java.text.ParseException; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.function.Consumer; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Boat; @@ -169,28 +170,42 @@ public interface DomainFactory { IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm, long timeoutInMilliseconds); /** - * Creates a {@link RaceDefinition} from a TracTrac {@link IRace} and a domain {@link Course} definition. The - * resulting {@link RaceDefinition} is added to the {@link com.sap.sailing.domain.base.Regatta} to which - * trackedRegatta belongs (see {@link TrackedRegatta#getRegatta()}). It is added to the internal race - * cache. The corresponding {@link TrackedRace} object is also created, and the notification of threads waiting on - * the race cache such as a blocking {@link #getAndWaitForRaceDefinition(UUID)} happens only after the - * tracked race has been created and the {@link RaceDefinition} was - * {@link com.sap.sailing.domain.base.Regatta#addRace(RaceDefinition) added} to the domain event. This ensures that - * waiters for the {@link RaceDefinition} are guaranteed to obtain a valid, non-null tracked race - * already immediately after the notification was sent, and that the {@link RaceDefinition} is already - * {@link com.sap.sailing.domain.base.Regatta#getAllRaces() known} by its containing - * {@link com.sap.sailing.domain.base.Regatta}. - * @param raceDefinitionSetToUpdate - * if not null, after creating the {@link TrackedRace}, the {@link RaceDefinition} is - * {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that - * object. - * @param raceLogResolver TODO - */ - DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId, - String raceName, Iterable competitors, BoatClass boatClass, Map competitorBoats, - Course course, Iterable sidelines, WindStore windStore, long delayToLiveInMillis, - long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, - URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings, RaceLogResolver raceLogResolver); + * Creates a {@link RaceDefinition} from a TracTrac {@link IRace} and a + * domain {@link Course} definition. The resulting {@link RaceDefinition} is + * added to the {@link com.sap.sailing.domain.base.Regatta} to which + * trackedRegatta belongs (see + * {@link TrackedRegatta#getRegatta()}). It is added to the internal race + * cache. The corresponding {@link TrackedRace} object is also created, and + * the notification of threads waiting on the race cache such as a blocking + * {@link #getAndWaitForRaceDefinition(UUID)} happens only after + * the tracked race has been created and the {@link RaceDefinition} was + * {@link com.sap.sailing.domain.base.Regatta#addRace(RaceDefinition) added} + * to the domain event. This ensures that waiters for the + * {@link RaceDefinition} are guaranteed to obtain a valid, + * non-null tracked race already immediately after the + * notification was sent, and that the {@link RaceDefinition} is already + * {@link com.sap.sailing.domain.base.Regatta#getAllRaces() known} by its + * containing {@link com.sap.sailing.domain.base.Regatta}. + * + * @param raceDefinitionSetToUpdate + * if not null, after creating the + * {@link TrackedRace}, the {@link RaceDefinition} is + * {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) + * added} to that object. + * @param runBeforeExposingRace + * if not {@code null} then this consumer will be passed the + * {@link DynamicTrackedRace} if it was actually created by this + * call. This happens while still in the + * {@code synchronized(raceCache)} block, therefore before calls + * waiting for the race (e.g., + * {@link #getAndWaitForRaceDefinition(UUID)}) return the race. + */ + DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId, + String raceName, Iterable competitors, BoatClass boatClass, + Map competitorBoats, Course course, Iterable sidelines, WindStore windStore, + long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, URI courseDesignUpdateURI, UUID tracTracEventUuid, + String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings, RaceLogResolver raceLogResolver, Consumer runBeforeExposingRace); /** * The record may be for a single mark or a gate. If for a gate, the @@ -256,12 +271,13 @@ public interface DomainFactory { * {@code File}) then if this parameter is {@code true} the race will be loaded from the replay file * instead of the {@code storedURI}/{@code liveURI} specified. This is particularly useful for restoring * races if since the last connection the race was migrated to a replay file format. + * @param timeoutInMillis TODO */ RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, - boolean preferReplayIfAvailable) throws Exception; + boolean preferReplayIfAvailable, int timeoutInMillis) throws Exception; /** * Removes all knowledge about tractracRace which includes removing it from the race cache, from the * {@link com.sap.sailing.domain.base.Regatta} and, if a {@link TrackedRace} for the corresponding diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java index 73c4570a572..3c093fc40ae 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java @@ -48,13 +48,12 @@ public interface TracTracAdapter { * @param timeoutInMilliseconds * if the race definition is not received for the race within this time, the race tracker for that race * is stopped; use -1 to wait forever - * @param trackWind TODO - * @param correctWindDirectionByMagneticDeclination TODO */ RaceHandle addTracTracRace(TrackerManager trackerManager, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds, String tracTracUsername, String tracTracPassword, String raceStatus, - String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception; + String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, int timeoutInMillis) + throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception; /** * Same as {@link #addTracTracRace(URL, URI, URI, WindStore, long)}, only that start and end of tracking are diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/AbstractReceiverWithQueue.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/AbstractReceiverWithQueue.java index 5f94f0cf790..c6d7e297bb9 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/AbstractReceiverWithQueue.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/AbstractReceiverWithQueue.java @@ -12,12 +12,12 @@ import java.util.logging.Logger; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sailing.domain.tracking.DynamicTrackedRegatta; -import com.sap.sailing.domain.tracking.RaceTracker; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.TrackedRegatta; import com.sap.sailing.domain.tractracadapter.DomainFactory; import com.sap.sailing.domain.tractracadapter.LoadingQueueDoneCallBack; import com.sap.sailing.domain.tractracadapter.Receiver; +import com.sap.sse.common.Duration; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Triple; import com.tractrac.model.lib.api.event.IEvent; @@ -35,7 +35,15 @@ import com.tractrac.subscription.lib.api.IRaceSubscriber; */ public abstract class AbstractReceiverWithQueue implements Runnable, Receiver { private static Logger logger = Logger.getLogger(AbstractReceiverWithQueue.class.getName()); - + + /** + * The timeout after which to re-try looking for the race definition to have appeared in + * {@link #getTrackedRace(IRace)} in case an infinite timeout (-1) was specified. During this + * short break, {@link #getTrackedRace(IRace)} will check for {@link #hasBeenStoppedPreemptively()} + * and will stop trying to look for the race if this received was stopped preemptively. + */ + private static final long RETRY_TIMEOUT_IN_MILLIS = Duration.ONE_MINUTE.asMillis(); + private final LinkedBlockingDeque> queue; private final DomainFactory domainFactory; private final IEvent tractracEvent; @@ -53,6 +61,14 @@ public abstract class AbstractReceiverWithQueue implements Runnable, Re */ private boolean receivedEventDuringTimeout; + /** + * Set by {@link #stopPreemptively()}. Invocations of {@link #handleEvent(Triple)} waiting for something + * should wait repeatedly with some timeout, such as, say, one minute, and keep re-trying until what they + * are waiting for has appeared, or this flag has been set in which case they can abort and assume they + * received a stop event. + */ + private boolean stoppedPreemptively; + public AbstractReceiverWithQueue(DomainFactory domainFactory, IEvent tractracEvent, DynamicTrackedRegatta trackedRegatta, Simulator simulator, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, long timeoutInMilliseconds) { @@ -97,6 +113,11 @@ public abstract class AbstractReceiverWithQueue implements Runnable, Re // mark the end and hence terminate the thread by adding a null/null/null event to the queue queue.clear(); stopAfterProcessingQueuedEvents(); + stoppedPreemptively = true; + } + + protected boolean hasBeenStoppedPreemptively() { + return stoppedPreemptively; } @Override @@ -195,15 +216,19 @@ public abstract class AbstractReceiverWithQueue implements Runnable, Re /** * Tries to find a {@link TrackedRace} for race in the {@link com.sap.sailing.domain.base.Regatta} * corresponding to {@link #tractracEvent}, as keyed by the {@link #domainFactory}. Waits for - * {@link RaceTracker#TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS} milliseconds for the - * {@link RaceDefinition} to show up. If it doesn't, null is returned. If the {@link RaceDefinition} - * for race is not found in the {@link com.sap.sailing.domain.base.Regatta}, null is - * returned. If the {@link TrackedRace} for race isn't found in the {@link TrackedRegatta}, - * null is returned, too. + * {@link #timeoutInMilliseconds} milliseconds for the {@link RaceDefinition} to show up, or infinitely if + * {@link #timeoutInMilliseconds} is -1, except this receiver is {@link #hasBeenStoppedPreemptively() stopped + * preemptively}. If the race doesn't show up under these boundary conditions, null is returned. If the + * {@link RaceDefinition} for race is not found in the {@link com.sap.sailing.domain.base.Regatta}, + * null is returned. If the {@link TrackedRace} for race isn't found in the + * {@link TrackedRegatta}, null is returned, too. */ protected DynamicTrackedRace getTrackedRace(IRace race) { DynamicTrackedRace result = null; - RaceDefinition raceDefinition = getDomainFactory().getAndWaitForRaceDefinition(race.getId(), timeoutInMilliseconds); + final long effectiveTimeoutInMilliseconds = timeoutInMilliseconds == -1 ? RETRY_TIMEOUT_IN_MILLIS : timeoutInMilliseconds; + RaceDefinition raceDefinition; + while ((raceDefinition = getDomainFactory().getAndWaitForRaceDefinition(race.getId(), effectiveTimeoutInMilliseconds)) == null && + timeoutInMilliseconds == -1 && !hasBeenStoppedPreemptively()); if (raceDefinition != null) { com.sap.sailing.domain.base.Regatta domainRegatta = trackedRegatta.getRegatta(); if (domainRegatta.getRaceByName(raceDefinition.getName()) != null) { diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java index 6178ce40ff6..4336c69a87c 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java @@ -18,8 +18,10 @@ import java.util.Map.Entry; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Stream; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Boat; @@ -386,9 +388,9 @@ public class DomainFactoryImpl implements DomainFactory { private Pair getDefaultRegattaNameAndBoatClass(IRace race) { Collection competitorClassList = new ArrayList<>(); - for (IRaceCompetitor competitor : race.getRaceCompetitors()) { + getCompetingCompetitors(race).forEach(competitor->{ competitorClassList.add(competitor.getCompetitor().getCompetitorClass()); - } + }); Pair defaultRegattaNameAndBoatClass = new Pair(race.getEvent().getName(), getDominantBoatClass(competitorClassList)); return defaultRegattaNameAndBoatClass; @@ -464,10 +466,6 @@ public class DomainFactoryImpl implements DomainFactory { } } if (raceDefinition != null) { - Collection competitorClassList = new ArrayList(); - for (IRaceCompetitor c : tractracRace.getRaceCompetitors()) { - competitorClassList.add(c.getCompetitor().getCompetitorClass()); - } // FIXME this only removes the race from its default regatta, not any explicit regatta Pair defaultRegattaNameAndBoatClass = getDefaultRegattaNameAndBoatClass(tractracRace); Pair key = new Pair(defaultRegattaNameAndBoatClass.getA(), @@ -510,11 +508,13 @@ public class DomainFactoryImpl implements DomainFactory { } @Override - public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId, - String raceName, Iterable competitors, BoatClass boatClass, Map competitorBoats, Course course, - Iterable sidelines, WindStore windStore, long delayToLiveInMillis, - long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, - URI tracTracUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings, RaceLogResolver raceLogResolver) { + public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId, + String raceName, Iterable competitors, BoatClass boatClass, + Map competitorBoats, Course course, Iterable sidelines, WindStore windStore, + long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, URI tracTracUpdateURI, UUID tracTracEventUuid, + String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings, RaceLogResolver raceLogResolver, + Consumer runBeforeExposingRace) { synchronized (raceCache) { RaceDefinition raceDefinition = raceCache.get(raceId); if (raceDefinition == null) { @@ -532,14 +532,25 @@ public class DomainFactoryImpl implements DomainFactory { delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, ignoreTracTracMarkPassings, raceLogResolver); logger.info("Added race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta()); + if (runBeforeExposingRace != null) { + logger.fine("Running callback for tracked race creation for "+trackedRace.getRace()); + runBeforeExposingRace.accept(trackedRace); + } addTracTracUpdateHandlers(tracTracUpdateURI, tracTracEventUuid, tracTracUsername, tracTracPassword, raceDefinition, trackedRace); raceCache.put(raceId, raceDefinition); raceCache.notifyAll(); } else { - logger.warning("Not adding race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta() + final String reasonForNotAddingRaceToRegatta = "Not adding race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta() + " because boat class " + raceDefinition.getBoatClass() - + " doesn't match regatta's boat class " + trackedRegatta.getRegatta().getBoatClass()); + + " doesn't match regatta's boat class " + trackedRegatta.getRegatta().getBoatClass(); + logger.warning(reasonForNotAddingRaceToRegatta); + try { + raceDefinitionSetToUpdate.raceNotLoaded(reasonForNotAddingRaceToRegatta); + } catch (Exception e) { + logger.log(Level.INFO, "Something else went wrong while trying to notify the RaceDefinition set that the race "+ + raceDefinition+" could not be added to the the regatta "+trackedRegatta.getRegatta(), e); + } } } else { logger.info("Found existing tracked race for race "+raceName+" with ID "+raceId); @@ -580,7 +591,7 @@ public class DomainFactoryImpl implements DomainFactory { @Override public Map getBoatsInfoForCompetitors(IRace race, BoatClass defaultBoatClass) { final Map competitorBoatInfos = new HashMap<>(); - for (IRaceCompetitor rc : race.getRaceCompetitors()) { + getCompetingCompetitors(race).forEach(rc->{ Util.Triple competitorBoatInfo = getMetadataParser().parseCompetitorBoat(rc); Competitor existingCompetitor = getOrCreateCompetitor(rc.getCompetitor()); if (existingCompetitor != null && competitorBoatInfo != null) { @@ -588,21 +599,28 @@ public class DomainFactoryImpl implements DomainFactory { competitorBoatInfo.getB(), AbstractColor.getCssColor(competitorBoatInfo.getC())); competitorBoatInfos.put(existingCompetitor, boatOfCompetitor); } - } + }); return competitorBoatInfos; } + /** + * Obtains those {@link IRace#getRaceCompetitors() competitors} that are actually competing in the race + * ({@link ICompetitor#isNonCompeting()}=={@code false}) + */ + private Stream getCompetingCompetitors(IRace race) { + return race.getRaceCompetitors().stream().filter(rc->!rc.getCompetitor().isNonCompeting()); + } @Override public Util.Pair, BoatClass> getCompetitorsAndDominantBoatClass(IRace race) { List competitorClasses = new ArrayList(); final List competitors = new ArrayList(); - for (IRaceCompetitor rc : race.getRaceCompetitors()) { + getCompetingCompetitors(race).forEach(rc->{ // also add those whose race class doesn't match the dominant one (such as camera boats) // because they may still send data that we would like to record in some tracks competitors.add(getOrCreateCompetitor(rc.getCompetitor())); competitorClasses.add(rc.getCompetitor().getCompetitorClass()); - } + }); BoatClass dominantBoatClass = getDominantBoatClass(competitorClasses); Util.Pair, BoatClass> competitorsAndDominantBoatClass = new com.sap.sse.common.Util.Pair, BoatClass>( competitors, dominantBoatClass); @@ -688,11 +706,11 @@ public class DomainFactoryImpl implements DomainFactory { URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String tracTracUsername, String tracTracPassword, String raceStatus, - String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, boolean preferReplayIfAvailable) throws Exception { + String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, boolean preferReplayIfAvailable, int timeoutInMillis) throws Exception { return new RaceTrackingConnectivityParametersImpl(paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, this, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination, - preferReplayIfAvailable); + preferReplayIfAvailable, timeoutInMillis); } @Override diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/MarkPassingReceiver.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/MarkPassingReceiver.java index 96b25bbbca3..d0a1b696ba1 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/MarkPassingReceiver.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/MarkPassingReceiver.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Map; import java.util.logging.Logger; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.tracking.DynamicTrackedRace; @@ -56,48 +55,49 @@ public class MarkPassingReceiver extends AbstractReceiverWithQueue event) { - System.out.print("L"); // as in "Leg" - DynamicTrackedRace trackedRace = getTrackedRace(event.getA().getRace()); - if (trackedRace != null) { - Course course = trackedRace.getRace().getCourse(); - Iterator waypointsIter = course.getWaypoints().iterator(); - Map passingsByWaypoint = new HashMap(); - // Note: the entries always describe all mark passings for the competitor so far in the current race in - // order - for (IControlPassing passing : event.getB().getPassings()) { - IControl controlPointPassed = passing.getControl(); - com.sap.sailing.domain.base.ControlPoint domainControlPoint = getDomainFactory() - .getOrCreateControlPoint(new ControlPointAdapter(controlPointPassed)); - Waypoint passed = findWaypointForControlPoint(trackedRace, waypointsIter, domainControlPoint, - getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor())); - if (passed != null) { - TimePoint time = new MillisecondsTimePoint(passing.getTimestamp()); - MarkPassing markPassing = getDomainFactory().createMarkPassing(time, passed, - getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor())); - passingsByWaypoint.put(passed, markPassing); - } else { - logger.warning("Didn't find waypoint in course " + course + " for mark passing around " - + passing.getControl()); - } - } - List markPassings = new ArrayList(); - for (Waypoint waypoint : course.getWaypoints()) { - MarkPassing passing = passingsByWaypoint.get(waypoint); - if (passing != null) { - markPassings.add(passing); - } - } - logger.fine("Received mark passings in race "+trackedRace.getRace().getName()+": "+markPassings); - if (getSimulator() != null) { - getSimulator().delayMarkPassings(getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor()), markPassings); - } else { - trackedRace.updateMarkPassings(getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor()), - markPassings); - } - } else { - logger.warning("Couldn't find tracked race for race " + event.getA().getRace().getName() - + ". Dropping mark passing event " + event); - } + if (!event.getA().getCompetitor().isNonCompeting()) { + System.out.print("L"); // as in "Leg" + DynamicTrackedRace trackedRace = getTrackedRace(event.getA().getRace()); + if (trackedRace != null) { + Course course = trackedRace.getRace().getCourse(); + Iterator waypointsIter = course.getWaypoints().iterator(); + Map passingsByWaypoint = new HashMap(); + // Note: the entries always describe all mark passings for the competitor so far in the current race in + // order + for (IControlPassing passing : event.getB().getPassings()) { + IControl controlPointPassed = passing.getControl(); + com.sap.sailing.domain.base.ControlPoint domainControlPoint = getDomainFactory() + .getOrCreateControlPoint(new ControlPointAdapter(controlPointPassed)); + Waypoint passed = findWaypointForControlPoint(trackedRace, waypointsIter, domainControlPoint); + if (passed != null) { + TimePoint time = new MillisecondsTimePoint(passing.getTimestamp()); + MarkPassing markPassing = getDomainFactory().createMarkPassing(time, passed, + getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor())); + passingsByWaypoint.put(passed, markPassing); + } else { + logger.warning("Didn't find waypoint in course " + course + " for mark passing around " + + passing.getControl()); + } + } + List markPassings = new ArrayList(); + for (Waypoint waypoint : course.getWaypoints()) { + MarkPassing passing = passingsByWaypoint.get(waypoint); + if (passing != null) { + markPassings.add(passing); + } + } + logger.fine("Received mark passings in race "+trackedRace.getRace().getName()+": "+markPassings); + if (getSimulator() != null) { + getSimulator().delayMarkPassings(getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor()), markPassings); + } else { + trackedRace.updateMarkPassings(getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor()), + markPassings); + } + } else { + logger.warning("Couldn't find tracked race for race " + event.getA().getRace().getName() + + ". Dropping mark passing event " + event); + } + } } /** @@ -106,7 +106,7 @@ public class MarkPassingReceiver extends AbstractReceiverWithQueuefalse. */ private Waypoint findWaypointForControlPoint(TrackedRace trackedRace, Iterator waypointsIter, - com.sap.sailing.domain.base.ControlPoint domainControlPoint, Competitor competitor) { + com.sap.sailing.domain.base.ControlPoint domainControlPoint) { while (waypointsIter.hasNext()) { Waypoint waypoint = waypointsIter.next(); if (waypoint.getControlPoint() == domainControlPoint) { diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java index 35b91110306..395fa7c48e3 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; @@ -135,7 +136,6 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueueupdateRaceTimes(tractracRace, tr)); } } catch (PatchFailedException e) { logger.log(Level.SEVERE, "Internal error updating race course "+course+": "+e.getMessage()); @@ -161,15 +160,11 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueueupdateRaceTimes(tractracRace, tr)); if (getSimulator() != null) { getSimulator().setTrackedRace(trackedRace); } } - if (needToUpdateRaceTimes) { - updateRaceTimes(tractracRace, trackedRace); - } } private void updateRaceTimes(IRace tractracRace, DynamicTrackedRace trackedRace) { @@ -222,11 +217,14 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue sidelines) { + private DynamicTrackedRace createTrackedRace(RaceDefinition race, Iterable sidelines, Consumer runAfterCreatingTrackedRace) { DynamicTrackedRace trackedRace = getTrackedRegatta().createTrackedRace(race, sidelines, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, /* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(), raceDefinitionSetToUpdate, useInternalMarkPassingAlgorithm, raceLogResolver); + if (runAfterCreatingTrackedRace != null) { + runAfterCreatingTrackedRace.accept(trackedRace); + } getDomainFactory().addTracTracUpdateHandlers(tracTracUpdateURI, getTracTracEvent().getId(), tracTracUsername, tracTracPassword, race, trackedRace); return trackedRace; } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceTrackingConnectivityParametersImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceTrackingConnectivityParametersImpl.java index eb1a614ecee..8e40864e068 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceTrackingConnectivityParametersImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceTrackingConnectivityParametersImpl.java @@ -5,6 +5,7 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.util.concurrent.TimeoutException; import java.util.logging.Logger; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; @@ -54,17 +55,24 @@ public class RaceTrackingConnectivityParametersImpl extends AbstractRaceTracking * {@code File}) then if this parameter is {@code true} the race will be loaded from the replay file * instead of the {@code storedURI}/{@code liveURI} specified. This is particularly useful for restoring * races if since the last connection the race was migrated to a replay file format. + * @param timeoutInMillis + * -1 means no timeout; otherwise, this is the timeout for waiting for the {@link IRace} to be obtained + * from the {@code paramURL} document. A {@link TimeoutException} will result if the timeout applied. */ public RaceTrackingConnectivityParametersImpl(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, DomainFactory domainFactory, String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility, - boolean trackWind, boolean correctWindDirectionByMagneticDeclination, boolean preferReplayIfAvailable) + boolean trackWind, boolean correctWindDirectionByMagneticDeclination, boolean preferReplayIfAvailable, int timeoutInMillis) throws Exception { super(trackWind, correctWindDirectionByMagneticDeclination); this.paramURL = paramURL; - this.tractracRace = ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())); + if (timeoutInMillis == -1) { + this.tractracRace = ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())); + } else { + this.tractracRace = ModelLocator.getEventFactory().createRace(new URI(paramURL.toString()), timeoutInMillis); + } if (preferReplayIfAvailable && isReplayRace(tractracRace) && (!Util.equalsWithNull(liveURI, tractracRace.getLiveURI()) || !Util.equalsWithNull(storedURI, tractracRace.getStoredURI()))) { logger.info("Replay format available and preferred for race " + tractracRace.getName() diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RawPositionReceiver.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RawPositionReceiver.java index 4e42bb0bac9..23b425d1dce 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RawPositionReceiver.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RawPositionReceiver.java @@ -48,25 +48,27 @@ public class RawPositionReceiver extends AbstractReceiverWithQueue event) { - if (received++ % 1000 == 0) { - System.out.print("P"); - if ((received / 1000 + 1) % 80 == 0) { - System.out.println(); - } - } - IRace race = event.getA().getRace(); - DynamicTrackedRace trackedRace = getTrackedRace(race); - if (trackedRace != null) { - final GPSFixMoving fix = getDomainFactory().createGPSFixMoving(event.getB()); - Competitor competitor = getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor()); - if (getSimulator() != null) { - getSimulator().scheduleCompetitorPosition(competitor, fix); - } else { - trackedRace.recordFix(competitor, fix); - } - } else { - logger.warning("Couldn't find tracked race for race " + race.getName() - + ". Dropping raw position event " + event); - } + if (!event.getA().getCompetitor().isNonCompeting()) { + if (received++ % 1000 == 0) { + System.out.print("P"); + if ((received / 1000 + 1) % 80 == 0) { + System.out.println(); + } + } + IRace race = event.getA().getRace(); + DynamicTrackedRace trackedRace = getTrackedRace(race); + if (trackedRace != null) { + final GPSFixMoving fix = getDomainFactory().createGPSFixMoving(event.getB()); + Competitor competitor = getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor()); + if (getSimulator() != null) { + getSimulator().scheduleCompetitorPosition(competitor, fix); + } else { + trackedRace.recordFix(competitor, fix); + } + } else { + logger.warning("Couldn't find tracked race for race " + race.getName() + + ". Dropping raw position event " + event); + } + } } } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracAdapterImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracAdapterImpl.java index 43a1aac95b6..9737d22380a 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracAdapterImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracAdapterImpl.java @@ -49,7 +49,7 @@ public class TracTracAdapterImpl implements TracTracAdapter { public RaceHandle addTracTracRace(TrackerManager trackerManager, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds, String tracTracUsername, String tracTracPassword, String raceStatus, - String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) throws Exception { + String raceVisibility, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, int timeoutInMillis) throws Exception { return trackerManager.addRace( /* regattaToAddTo */null, getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI, @@ -57,7 +57,7 @@ public class TracTracAdapterImpl implements TracTracAdapter { /* startOfTracking */null, /* endOfTracking */null, delayToLiveInMillis, /* offsetToStartTimeOfSimulatedRace */null, /* ignoreTracTracMarkPassings */ false, raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination, - /* preferReplayIfAvailable */ false), + /* preferReplayIfAvailable */ false, timeoutInMillis), timeoutInMilliseconds); } @@ -73,7 +73,8 @@ public class TracTracAdapterImpl implements TracTracAdapter { getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword, - raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination, /* preferReplayIfAvailable */ false), timeoutInMilliseconds); + raceStatus, raceVisibility, trackWind, correctWindDirectionByMagneticDeclination, /* preferReplayIfAvailable */ false, + (int) timeoutInMilliseconds), timeoutInMilliseconds); } @Override diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java index 0dd509d1469..ee38f2a7e29 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java @@ -334,10 +334,12 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl eventSubscriber.subscribeCompetitors(new ICompetitorsListener() { @Override public void updateCompetitor(ICompetitor competitor) { - final Competitor domainCompetitor = TracTracRaceTrackerImpl.this.domainFactory.getOrCreateCompetitor(competitor); - logger.info("Competitor "+competitor+" was updated on TracTrac side. Maybe consider updating in competitor store as well. "+ - "TracTrac competitor maps to "+domainCompetitor.getName()+" with sail ID "+domainCompetitor.getBoat().getSailID()+ - " and boat class "+domainCompetitor.getBoat().getBoatClass().getName()); + if (!competitor.isNonCompeting()) { + final Competitor domainCompetitor = TracTracRaceTrackerImpl.this.domainFactory.getOrCreateCompetitor(competitor); + logger.info("Competitor "+competitor+" was updated on TracTrac side. Maybe consider updating in competitor store as well. "+ + "TracTrac competitor maps to "+domainCompetitor.getName()+" with sail ID "+domainCompetitor.getBoat().getSailID()+ + " and boat class "+domainCompetitor.getBoat().getBoatClass().getName()); + } } @Override @@ -647,6 +649,16 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl notifyRaceCreationListeners(); } + /** + * When this tracker is informed that the race cannot be loaded, e.g., because its boat class does + * not match the regatta's boat class, the tracker will {@link #stop} preemptively. + */ + @Override + public void raceNotLoaded(String reason) throws MalformedURLException, IOException, InterruptedException { + logger.severe("Race for tracker "+this+" with ID "+getID()+" did not load: "+reason+". Stopping tracker."); + trackedRegattaRegistry.stopTracking(regatta, race); + } + @Override public void gotLiveDataEvent(ILiveDataEvent liveDataEvent) { logger.info("Status change in tracker "+getID()+" for race(s) "+getRace()+": "+liveDataEvent); diff --git a/java/com.sap.sailing.domain/.settings/org.eclipse.core.resources.prefs b/java/com.sap.sailing.domain/.settings/org.eclipse.core.resources.prefs new file mode 100755 index 00000000000..c12fb7f58f3 --- /dev/null +++ b/java/com.sap.sailing.domain/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//src/com/sap/sailing/domain/base/impl/KilometersPerHourSpeedWithBearingImpl.java=UTF-8 diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java index 0e51ef84538..74e0c69545b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java @@ -43,6 +43,7 @@ import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOver import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10LastBreaksTie; import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10Or8AndLastBreaksTie; import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets12Or8AndLastBreaksTie; +import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets12Or8AndLastBreaksTie2017; import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets1LastBreaksTie; import com.sap.sailing.domain.leaderboard.impl.HighPointLastBreaksTie; import com.sap.sailing.domain.leaderboard.impl.HighPointWinnerGetsEight; @@ -124,6 +125,8 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain return new HighPointFirstGets10Or8AndLastBreaksTie(); case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT: return new HighPointFirstGets12Or8AndLastBreaksTie(); + case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017: + return new HighPointFirstGets12Or8AndLastBreaksTie2017(); case LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07: return new LowPointWithEliminationsAndRoundsWinnerGets07(); case LOW_POINT_LEAGUE_OVERALL: diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/KilometersPerHourSpeedWithBearingImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/KilometersPerHourSpeedWithBearingImpl.java index 0a21afa70b2..20df8ab0b43 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/KilometersPerHourSpeedWithBearingImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/KilometersPerHourSpeedWithBearingImpl.java @@ -46,7 +46,7 @@ public class KilometersPerHourSpeedWithBearingImpl extends KilometersPerHourSpee @Override public String toString() { - return super.toString()+" to "+getBearing().getDegrees()+"�"; + return super.toString()+" to "+getBearing().getDegrees()+"°"; } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java index e704b9dbbd5..1bfd15ca2b5 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java @@ -175,7 +175,7 @@ public class LeaderboardCacheManager { } @Override - public void correctedScoreChanced(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore) { + public void correctedScoreChanged(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore) { removeFromCache(leaderboard); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/NumberOfCompetitorsInLeaderboardFetcher.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/NumberOfCompetitorsInLeaderboardFetcher.java index 38e15133338..a42d94247c5 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/NumberOfCompetitorsInLeaderboardFetcher.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/NumberOfCompetitorsInLeaderboardFetcher.java @@ -1,6 +1,8 @@ package com.sap.sailing.domain.leaderboard; +import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.leaderboard.impl.AbstractSimpleLeaderboardImpl; +import com.sap.sse.common.TimePoint; /** * Computing the competitors can be a bit expensive, particularly if the fleet is large and there may be suppressed @@ -23,4 +25,5 @@ import com.sap.sailing.domain.leaderboard.impl.AbstractSimpleLeaderboardImpl; */ public interface NumberOfCompetitorsInLeaderboardFetcher { int getNumberOfCompetitorsInLeaderboard(); + int getNumberOfCompetitorsWithoutMaxPointReason(RaceColumn column, TimePoint timePoint); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrectionListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrectionListener.java index eb64022400d..5c19bb38b91 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrectionListener.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrectionListener.java @@ -6,7 +6,7 @@ import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sse.common.TimePoint; public interface ScoreCorrectionListener { - void correctedScoreChanced(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore); + void correctedScoreChanged(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore); void maxPointsReasonChanced(Competitor competitor, RaceColumn raceColumn, MaxPointsReason oldMaxPointsReason, MaxPointsReason newMaxPointsReason); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoringScheme.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoringScheme.java index 825b3b1ab20..db4c77d410e 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoringScheme.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoringScheme.java @@ -66,9 +66,12 @@ public interface ScoringScheme extends Serializable { * otherwise, this parameter tells the number of competitors in the same race as competitor, * not in the entire raceColumn (those may be more in case of split fleets). The scoring scheme * may use this number, if available, to infer a penalty score. + * @param timePoint + * an optional timePoint that may help the scheme to determine the penalty related to a certain point in time only. */ Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason, - Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher); + Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, + TimePoint timePoint); /** * @param competitor1Scores scores of the first competitor, in the order of race columns in the leaderboard diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index d24c4c15781..51497d42743 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -252,6 +252,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race */ public class NumberOfCompetitorsFetcherImpl implements NumberOfCompetitorsInLeaderboardFetcher { private int numberOfCompetitors = -1; + private int numberOfCompetitorsWithoutMaxPointReason = -1; @Override public int getNumberOfCompetitorsInLeaderboard() { @@ -260,6 +261,18 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race } return numberOfCompetitors; } + + @Override + public int getNumberOfCompetitorsWithoutMaxPointReason(RaceColumn column, TimePoint timePoint) { + if (numberOfCompetitorsWithoutMaxPointReason == -1) { + numberOfCompetitorsWithoutMaxPointReason = 0; + for (Competitor competitor : getCompetitors()) { + MaxPointsReason maxPointReason = getScoreCorrection().getMaxPointsReason(competitor, column, timePoint); + numberOfCompetitorsWithoutMaxPointReason += maxPointReason == MaxPointsReason.NONE ? 1 : 0; + } + } + return numberOfCompetitorsWithoutMaxPointReason; + } } /** @@ -1200,6 +1213,9 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race @Override public void setSuppressed(Competitor competitor, boolean suppressed) { + if (competitor == null) { + throw new IllegalArgumentException("Cannot change suppression for a null competitor"); + } LockUtil.lockForWrite(suppressedCompetitorsLock); try { if (suppressed) { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPoint.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPoint.java index a6eb7de1f08..8afd1fb433f 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPoint.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPoint.java @@ -64,7 +64,7 @@ public class HighPoint extends AbstractScoringSchemeImpl { @Override public Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason, Integer numberOfCompetitorsInRace, - NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) { + NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) { return 0.0; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGets12Or8AndLastBreaksTie2017.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGets12Or8AndLastBreaksTie2017.java new file mode 100644 index 00000000000..52fe2556579 --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGets12Or8AndLastBreaksTie2017.java @@ -0,0 +1,61 @@ +package com.sap.sailing.domain.leaderboard.impl; + +import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.common.MaxPointsReason; +import com.sap.sailing.domain.common.ScoringSchemeType; +import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher; +import com.sap.sse.common.TimePoint; + +/** + * {@link HighPointFirstGetsFixedScore} scheme that in most cases applies + * 12 points for the winner. Iff for one race column a {@link RaceLogAdditionalScoringInformationEvent} + * is found then 8 points are applied for the winner. + * + * From Phil, Race Director, on 12.09.2014: "If there is a tie in the regatta score between two or more boats at any time, the tie + * shall be broken in favour of the boat that has won the most races. If a tie still remains, it shall be broken in + * favour of the boat that had the better place at the last race sailed." + * + * 13.1.2 A Boat that did not start, did not finish, or retired shall receive 1 point less than the last boat to complete the race. + * 13.1.3 A Boat that is disqualified from a race, including OCS, shall receive 2 points less than the last boat to complete the race. + * + * @author Simon Marcel Pamies + */ +public class HighPointFirstGets12Or8AndLastBreaksTie2017 extends AbstractHighPointFirstGetsFixedOr8AndLastBreaksTie { + private static final long serialVersionUID = 1L; + + public HighPointFirstGets12Or8AndLastBreaksTie2017() { + super(12.0); + } + + @Override + public ScoringSchemeType getType() { + return ScoringSchemeType.HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017; + } + + @Override + public Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason, + Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) { + Double result; + /** + * 1. Get all competitors without a max point reason. + * 2. This list of competitors is assumed to be all competitors having successfully taken part in the race. + * 3. The score of the last competitor will be 12-size(competitorList) + * + * XXX How about two competitors not finishing a race? They will get the same score. NOR does not state + * anything on how to handle such a situation except that it implicates that this will lead to a tie. No + * update from OC Sport on that question so far (Mar 2017). + */ + int competitorCountWithoutMaxPointReason = numberOfCompetitorsInLeaderboardFetcher.getNumberOfCompetitorsWithoutMaxPointReason(raceColumn, timePoint); + if (maxPointsReason == MaxPointsReason.DNS || maxPointsReason == MaxPointsReason.DNF || maxPointsReason == MaxPointsReason.RET) { + result = (12 - competitorCountWithoutMaxPointReason) * 1.0; + } else if (maxPointsReason == MaxPointsReason.DSQ || maxPointsReason == MaxPointsReason.OCS) { + result = (12 - competitorCountWithoutMaxPointReason - 1) * 1.0; + } else { + result = 0.0; + } + return result; + } + +} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGets1LastBreaksTie.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGets1LastBreaksTie.java index 9d4d86e0ac5..fb7b38a22d8 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGets1LastBreaksTie.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGets1LastBreaksTie.java @@ -24,7 +24,7 @@ public class HighPointFirstGets1LastBreaksTie extends HighPointFirstGetsFixedSco @Override public Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason, Integer numberOfCompetitorsInRace, - NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) { + NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) { return -1.0; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPoint.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPoint.java index 3c4a9e7c02b..e578674915c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPoint.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPoint.java @@ -57,7 +57,7 @@ public class LowPoint extends AbstractScoringSchemeImpl { @Override public Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason, - Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) { + Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) { Double result; if (numberOfCompetitorsInRace == null || raceColumn.hasSplitFleetContiguousScoring()) { result = (double) (numberOfCompetitorsInLeaderboardFetcher.getNumberOfCompetitorsInLeaderboard()+1); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java index 6cb3fece26c..f674cffd02e 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java @@ -99,7 +99,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection { protected void notifyListeners(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore) { for (ScoreCorrectionListener listener : getScoreCorrectionListeners()) { - listener.correctedScoreChanced(competitor, raceColumn, oldCorrectedScore, newCorrectedScore); + listener.correctedScoreChanged(competitor, raceColumn, oldCorrectedScore, newCorrectedScore); } } @@ -330,7 +330,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection { } } - private AnnotatedMaxPointsReason getAnnotatedMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) { + protected AnnotatedMaxPointsReason getAnnotatedMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) { MaxPointsReason maxPointsReason = maxPointsReasons.get(raceColumn.getKey(competitor)); boolean maxPointsReasonExistsButIsNotApplicableForTimePoint; if (maxPointsReason == null) { @@ -390,7 +390,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection { if (correctedNonMaxedScore == null) { result = scoringScheme.getPenaltyScore(raceColumn, competitor, maxPointsReason.getMaxPointsReason(), getNumberOfCompetitorsInRace(raceColumn, competitor, numberOfCompetitorsInLeaderboardFetcher), - numberOfCompetitorsInLeaderboardFetcher); + numberOfCompetitorsInLeaderboardFetcher, timePoint); } else { result = correctedNonMaxedScore; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java index 460ab3af697..6c0ad316647 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java @@ -69,7 +69,7 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI private static final long serialVersionUID = 915433462154943441L; @Override - public void correctedScoreChanced(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore) { + public void correctedScoreChanged(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore) { getScoreCorrection().notifyListeners(competitor, raceColumn, oldCorrectedScore, newCorrectedScore); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java index cb4fe3f7377..1a16c789ebc 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java @@ -286,7 +286,6 @@ public class TopLevelMasterData implements Serializable { for (RegattaAndRaceIdentifier raceIdentifier : mediaTrack.assignedRaces) { if (raceIdentitifiersForMediaExport.contains(raceIdentifier)) { filteredMediaTracks.add(mediaTrack); - continue; } } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicRaceDefinitionSet.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicRaceDefinitionSet.java index a9497e47c14..097605f75fd 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicRaceDefinitionSet.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicRaceDefinitionSet.java @@ -18,4 +18,11 @@ import com.sap.sailing.domain.base.RaceDefinition; @FunctionalInterface public interface DynamicRaceDefinitionSet { void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace); + + /** + * Called when the race has not or can not be loaded. A {@code reason} may be provided or may be left {@code null}. + * This default implementation does nothing. Implementing classes may choose, e.g., to stop all further efforts + * trying to track the race. + */ + default void raceNotLoaded(String reason) throws Exception {} } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTracker.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTracker.java index 6e1a4a258de..77ef2459eac 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTracker.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTracker.java @@ -9,8 +9,8 @@ import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; /** - * Centerpiece of a tracking adapter. A tracker is responsible for receiving tracking data for one or more - * {@link RaceDefinition races} that are {@link Regatta#getAllRaces() part of} a common {@link #getRegatta() Event}. Some + * Centerpiece of a tracking adapter. A tracker is responsible for receiving tracking data for one + * {@link RaceDefinition race} that is {@link Regatta#getAllRaces() part of} a common {@link #getRegatta() Event}. Some * tracker architectures may not be able to deliver all data for the {@link RaceDefinition} when created or started. * Therefore, {@link #getRace()} may return null if the race information hasn't been received by the * tracker yet. Through the {@link RaceHandle} returned by {@link #getRaceHandle()} it is also possible to perform a @@ -43,7 +43,7 @@ public interface RaceTracker { static long TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS = 60000; /** - * Stops tracking the races. + * Stops tracking the race. * * @param preemptive * if false, the tracker will continue to process data already received but will stop @@ -55,7 +55,7 @@ public interface RaceTracker { com.sap.sailing.domain.base.Regatta getRegatta(); /** - * Returns the races being tracked by this tracker, in a "volatile" way, meaning that if another thread belonging to + * Returns the race being tracked by this tracker, in a "volatile" way, meaning that if another thread belonging to * this tracker has established the {@link RaceDefinition} for this tracker, other threads will immediately see this * object. Non-blocking call that returns null if the {@link RaceDefinition} hasn't been created yet, * e.g., because the course definition hasn't been received yet or the listener for receiving course information diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParameters.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParameters.java index cb965645a2a..8925987ff89 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParameters.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParameters.java @@ -25,7 +25,13 @@ public interface RaceTrackingConnectivityParameters { * {@link Regatta} is provided, this will first look up a regatta for the race from * {@link TrackedRegattaRegistry#getRememberedRegattaForRace(java.io.Serializable)} and if not found will look up or * create a default regatta based on race data such as an event name and the boat class. - * @param timeoutInMilliseconds TODO + * + * @param timeoutInMilliseconds + * gives the tracker a possibility to abort tracking the race after so many milliseconds of + * unsuccessfully waiting for the connection to be established. Support is optional for + * implementations, and there is no exact specification what must have happened before + * this timeout in order for tracking to continue. So, consider this as a "hint" to the + * tracker. */ RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, RaceLogResolver raceLogResolver, long timeoutInMilliseconds) throws Exception; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParametersHandler.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParametersHandler.java index 1e7e0d9ea4c..87d91de2ac3 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParametersHandler.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParametersHandler.java @@ -34,6 +34,9 @@ public interface RaceTrackingConnectivityParametersHandler { * finding} this service instance in the first place. The object returned is equivalent to one that has * produced {@code map} by passing it to this service's {@link #mapFrom(RaceTrackingConnectivityParameters)} * method. + * + * @return {@code null} in case the object cannot be produced, e.g., because the leaderboard to which a + * race log-tracked race belonged has been deleted in the meantime. */ RaceTrackingConnectivityParameters mapTo(Map map) throws Exception; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/SensorFixTrack.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/SensorFixTrack.java index 53b7498d35e..1a41790f618 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/SensorFixTrack.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/SensorFixTrack.java @@ -16,13 +16,6 @@ import com.sap.sse.common.WithID; public interface SensorFixTrack extends MappedTrack { - /** - * Value names to be used when reading values from {@link SensorFix}es by calling {@link SensorFix#get(String)}. - * - * @return the value names that fixes contained in this track support - */ - Iterable getValueNames(); - void addListener(SensorFixTrackListener listener); void removeListener(SensorFixTrackListener listener); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/BravoFixTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/BravoFixTrackImpl.java index 379c114418b..c405f0934f2 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/BravoFixTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/BravoFixTrackImpl.java @@ -3,7 +3,6 @@ package com.sap.sailing.domain.tracking.impl; import java.io.Serializable; import com.sap.sailing.domain.common.Distance; -import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata; import com.sap.sailing.domain.common.tracking.BravoFix; import com.sap.sailing.domain.tracking.BravoFixTrack; import com.sap.sailing.domain.tracking.DynamicBravoFixTrack; @@ -28,8 +27,7 @@ public class BravoFixTrackImpl extends S * the name of the track by which it can be obtained from the {@link TrackedRace}. */ public BravoFixTrackImpl(ItemType trackedItem, String trackName) { - super(trackedItem, trackName, BravoSensorDataMetadata.INSTANCE.getFileColumns(), - BravoFixTrack.TRACK_NAME + " for " + trackedItem); + super(trackedItem, trackName, BravoFixTrack.TRACK_NAME + " for " + trackedItem); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java index a3b7963da9c..d23a2aa12f3 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java @@ -3,6 +3,8 @@ package com.sap.sailing.domain.tracking.impl; import java.util.ArrayList; import java.util.List; import java.util.NavigableSet; +import java.util.logging.Level; +import java.util.logging.Logger; import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence; import com.sap.sailing.domain.base.SpeedWithConfidence; @@ -13,6 +15,7 @@ import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.confidence.BearingWithConfidence; import com.sap.sailing.domain.common.confidence.BearingWithConfidenceCluster; import com.sap.sailing.domain.common.confidence.ConfidenceBasedAverager; @@ -22,23 +25,62 @@ import com.sap.sailing.domain.common.confidence.Weigher; import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.tracking.GPSFixMoving; -import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl; +import com.sap.sailing.domain.common.tracking.impl.CompactPositionHelper; +import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException; +import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; import com.sap.sse.common.TimePoint; public class DynamicGPSFixMovingTrackImpl extends GPSFixTrackImpl implements DynamicGPSFixTrack { + private static final Logger logger = Logger.getLogger(DynamicGPSFixMovingTrackImpl.class.getName()); + private static final long serialVersionUID = 9111448573301259784L; private static final double MAX_SPEED_FACTOR_COMPARED_TO_MEASURED_SPEED_FOR_FILTERING = 2; + /** + * Uses lossy compaction of fixes. See {@link CompactPositionHelper}. Use {@link #DynamicGPSFixMovingTrackImpl(Object, long, boolean)} + * to configure lossless compaction. + */ public DynamicGPSFixMovingTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage) { - super(trackedItem, millisecondsOverWhichToAverage); + this(trackedItem, millisecondsOverWhichToAverage, /* losslessCompaction */ false); } /** - * @param maxSpeedForSmoothening pass null if you don't want speed-based smoothening + * Uses lossy compaction. Use {@link #DynamicGPSFixMovingTrackImpl(Object, long, Speed, boolean)} to configure + * lossless compaction. + * + * @param maxSpeedForSmoothening + * pass null if you don't want speed-based smoothening */ public DynamicGPSFixMovingTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, Speed maxSpeedForSmoothening) { - super(trackedItem, millisecondsOverWhichToAverage, maxSpeedForSmoothening); + this(trackedItem, millisecondsOverWhichToAverage, maxSpeedForSmoothening, /* losslessCompaction */ false); + } + + /** + * @param maxSpeedForSmoothening + * pass null if you don't want speed-based smoothening + * @param losslessCompaction + * If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely equal to + * their original, without rounding or range limitations different from those of the original + * {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that, however, has + * stricter limits on ranges and precisions. See {@link CompactPositionHelper} for details on lossy + * compaction. + */ + public DynamicGPSFixMovingTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, Speed maxSpeedForSmoothening, boolean losslessCompaction) { + super(trackedItem, millisecondsOverWhichToAverage, maxSpeedForSmoothening, losslessCompaction); + } + + /** + * @param losslessCompaction + * If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely equal to + * their original, without rounding or range limitations different from those of the original + * {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that, however, has + * stricter limits on ranges and precisions. See {@link CompactPositionHelper} for details on lossy + * compaction. + */ + public DynamicGPSFixMovingTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, boolean losslessCompaction) { + super(trackedItem, millisecondsOverWhichToAverage, losslessCompaction); } /** @@ -57,7 +99,14 @@ public class DynamicGPSFixMovingTrackImpl extends GPSFixTrackImpl extends GPSFixTrackImpl implements DynamicGPSFixTrack { private static final long serialVersionUID = 4035953954507697564L; + /** + * By default uses lossy compaction. See {@link CompactPositionHelper}. + */ public DynamicGPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage) { - super(trackedItem, millisecondsOverWhichToAverage); + this(trackedItem, millisecondsOverWhichToAverage, /* losslessCompaction */ false); + } + + public DynamicGPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, boolean losslessCompaction) { + super(trackedItem, millisecondsOverWhichToAverage, losslessCompaction); } public void addGPSFix(GPSFix gpsFix) { @@ -22,7 +31,8 @@ public class DynamicGPSFixTrackImpl extends GPSFixTrackImpl { final TimePoint fixTimePoint = fix.getTimePoint(); if (!onlyWhenInTrackingTimeInterval || isWithinStartAndEndOfTracking(fixTimePoint)) { getOrCreateTrack(mark).addGPSFix(fix); + } else { + logger.finer(() -> "Dropped fix " + fix + " because it is outside the tracking interval " + + getStartOfTracking() + ".." + getEndOfTracking()); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java index 12e0b505735..73f586e75d6 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java @@ -22,6 +22,7 @@ import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.TrackedRaceStatusEnum; +import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.confidence.BearingWithConfidence; import com.sap.sailing.domain.common.confidence.BearingWithConfidenceCluster; import com.sap.sailing.domain.common.confidence.ConfidenceBasedAverager; @@ -34,6 +35,7 @@ import com.sap.sailing.domain.common.impl.NauticalMileDistance; import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.WithValidityCache; +import com.sap.sailing.domain.common.tracking.impl.CompactPositionHelper; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.GPSTrackListener; import com.sap.sailing.domain.tracking.TrackedRace; @@ -45,7 +47,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.TimeRangeImpl; import com.sap.sse.util.impl.ArrayListNavigableSet; -public class GPSFixTrackImpl extends MappedTrackImpl +public abstract class GPSFixTrackImpl extends MappedTrackImpl implements GPSFixTrack { private static final Logger logger = Logger.getLogger(GPSFixTrackImpl.class.getName()); private static final long serialVersionUID = 2115321069242514378L; @@ -121,8 +123,25 @@ public class GPSFixTrackImpl extends MappedTra private int estimatedSpeedCacheHits; private int estimatedSpeedCacheMisses; - public GPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage) { - this(trackedItem, millisecondsOverWhichToAverage, DEFAULT_MAX_SPEED_FOR_SMOOTHING); + /** + * If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely + * equal to their original, without rounding or range limitations different from those of the + * original {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that, + * however, has stricter limits on ranges and precisions. See {@link CompactPositionHelper} for + * details on lossy compaction. + */ + private final boolean losslessCompaction; + + /** + * @param losslessCompaction + * If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely equal to + * their original, without rounding or range limitations different from those of the original + * {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that, however, has + * stricter limits on ranges and precisions. See {@link CompactPositionHelper} for details on lossy + * compaction. + */ + protected GPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, boolean losslessCompaction) { + this(trackedItem, millisecondsOverWhichToAverage, DEFAULT_MAX_SPEED_FOR_SMOOTHING, losslessCompaction); } /** @@ -130,7 +149,7 @@ public class GPSFixTrackImpl extends MappedTra * if null, any fix speed will be accepted as long as fix-provided speed (if any) and * inferred speed can be matched. */ - public GPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, Speed maxSpeedForSmoothening) { + protected GPSFixTrackImpl(ItemType trackedItem, long millisecondsOverWhichToAverage, Speed maxSpeedForSmoothening, boolean losslessCompaction) { super(trackedItem, /* nameForReadWriteLock */ GPSFixTrackImpl.class.getSimpleName() + (trackedItem == null ? "" : (" for " + trackedItem.toString()))); this.millisecondsOverWhichToAverage = millisecondsOverWhichToAverage; @@ -139,8 +158,13 @@ public class GPSFixTrackImpl extends MappedTra this.distanceCache = new DistanceCache(trackedItem==null?"null":trackedItem.toString()); this.maxSpeedCache = createMaxSpeedCache(); this.validityCachingSuspended = false; + this.losslessCompaction = losslessCompaction; } - + + protected boolean isLosslessCompaction() { + return losslessCompaction; + } + @Override public void suspendValidityCaching() { validityCachingSuspended = true; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/SensorFixTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/SensorFixTrackImpl.java index dd4b5984764..c72d285ad50 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/SensorFixTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/SensorFixTrackImpl.java @@ -21,21 +21,17 @@ public class SensorFixTrackImpl valueNames; private final String trackName; private final TrackListenerCollection> listeners; /** * @param trackedItem the item this track is mapped to * @param trackName the name of the track by which it can be obtained from the {@link TrackedRace}. - * @param valueNames the name of the values that can be obtained by fixes contained in the track * @param nameForReadWriteLock the name to use for the lock object that is used internally */ - public SensorFixTrackImpl(ItemType trackedItem, String trackName, Iterable valueNames, - String nameForReadWriteLock) { + public SensorFixTrackImpl(ItemType trackedItem, String trackName, String nameForReadWriteLock) { super(trackedItem, nameForReadWriteLock); this.trackName = trackName; - this.valueNames = valueNames; this.listeners = new TrackListenerCollection<>(); } @@ -57,11 +53,6 @@ public class SensorFixTrackImpl getValueNames() { - return valueNames; - } - @Override public void addListener(SensorFixTrackListener listener) { this.listeners.addListener(listener); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index c7ed52457f1..576a9768a73 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -790,7 +790,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl boolean startOfTrackingFound = false; boolean endOfTrackingFound = false; // check race log - if (trackingTimesFromRaceLog != null){ + if (trackingTimesFromRaceLog != null) { if (trackingTimesFromRaceLog.getA() != null) { startOfTracking = trackingTimesFromRaceLog.getA().getTimePoint(); startOfTrackingFound = true; @@ -971,8 +971,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } startTime = newStartTime; startTimeWithoutInferenceFromStartMarkPassings = newStartTimeWithoutInferenceFromStartMarkPassings; - } } + } /** * Calculates the end time of the race from the mark passings of the last course waypoint @@ -2852,8 +2852,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } private List extractInterval(TimePoint from, TimePoint to, List listOfTimed) { - List result; - result = new LinkedList(); + List result = new LinkedList(); for (T timed : listOfTimed) { if (timed.getTimePoint().compareTo(from) >= 0 && timed.getTimePoint().compareTo(to) <= 0) { result.add(timed); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindTrackImpl.java index 9f0e79a70a4..82a9a479a89 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindTrackImpl.java @@ -19,7 +19,10 @@ import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.confidence.impl.PositionAndTimePointWeigher; -import com.sap.sailing.domain.common.tracking.impl.CompactWindImpl; +import com.sap.sailing.domain.common.tracking.impl.CompactPositionHelper; +import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException; +import com.sap.sailing.domain.common.tracking.impl.PreciseCompactWindImpl; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl; import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager; import com.sap.sailing.domain.confidence.ConfidenceFactory; import com.sap.sailing.domain.tracking.WindListener; @@ -56,11 +59,23 @@ public class WindTrackImpl extends TrackImpl implements WindTrack { */ private transient Set listeners; + /** + * If {@code true}, {@link Wind} fixes will be compacted in a way that they remain precisely + * equal to their original, without rounding or range limitations different from those of the + * original {@link Wind} fix. Lossy compaction, in contrast, may use a more compact form that, + * however, has stricter limits on ranges and precisions. See {@link CompactPositionHelper} for + * details on lossy compaction. + */ + private final boolean losslessCompaction; + public WindTrackImpl(long millisecondsOverWhichToAverage, boolean useSpeed, String nameForReadWriteLock) { this(millisecondsOverWhichToAverage, DEFAULT_BASE_CONFIDENCE, useSpeed, nameForReadWriteLock); } /** + * Uses lossy compaction. See {@link CompactPositionHelper}. Use {@link #WindTrackImpl(long, double, boolean, String, boolean)} + * to select lossless compaction. + * * @param baseConfidence * the confidence to attribute to the raw wind fixes in this track * @param useSpeed @@ -69,11 +84,29 @@ public class WindTrackImpl extends TrackImpl implements WindTrack { * value for the speed */ public WindTrackImpl(long millisecondsOverWhichToAverage, double baseConfidence, boolean useSpeed, String nameForReadWriteLock) { + this(millisecondsOverWhichToAverage, baseConfidence, useSpeed, nameForReadWriteLock, /* losslessCompaction */ false); + } + + /** + * Uses lossy compaction. See {@link CompactPositionHelper}. + * + * @param baseConfidence + * the confidence to attribute to the raw wind fixes in this track + * @param useSpeed + * whether the wind speed described by the fixes in this track are usable at all; example for an unusable + * wind speed would be that of an estimation that only estimates the wind direction and uses some default + * value for the speed + * @param losslessCompaction + * whether or not to use lossless compaction; see {@link CompactPositionHelper} for details on lossy + * compaction + */ + public WindTrackImpl(long millisecondsOverWhichToAverage, double baseConfidence, boolean useSpeed, String nameForReadWriteLock, boolean losslessCompaction) { super(new ArrayListNavigableSet(WindComparator.INSTANCE), nameForReadWriteLock); this.baseConfidence = baseConfidence; this.millisecondsOverWhichToAverage = millisecondsOverWhichToAverage; listeners = new HashSet(); this.useSpeed = useSpeed; + this.losslessCompaction = losslessCompaction; } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { @@ -114,12 +147,23 @@ public class WindTrackImpl extends TrackImpl implements WindTrack { @Override public boolean add(Wind wind, boolean replace) { - final CompactWindImpl compactWind = new CompactWindImpl(wind); + final Wind compactWind = compactify(wind); final boolean result = super.add(compactWind, replace); notifyListenersAboutReceive(compactWind); return result; } + private Wind compactify(Wind wind) { + Wind compactWind; + try { + compactWind = losslessCompaction ? new PreciseCompactWindImpl(wind) : new VeryCompactWindImpl(wind); + } catch (CompactionNotPossibleException e) { + logger.log(Level.FINE, "Couldn't compact wind fix "+wind+". Using lossless compactification instead.", e); + compactWind = new PreciseCompactWindImpl(wind); + } + return compactWind; + } + private void notifyListenersAboutReceive(Wind wind) { synchronized (listeners) { for (WindListener listener : listeners) { @@ -420,7 +464,8 @@ public class WindTrackImpl extends TrackImpl implements WindTrack { public void remove(Wind wind) { lockForWrite(); try { - getInternalRawFixes().remove(wind); + // map through "compactify" to account for possible rounding / accuracy differences and still achieve "equals" + getInternalRawFixes().remove(compactify(wind)); } finally { unlockAfterWrite(); } diff --git a/java/com.sap.sailing.gwt.ui.test/.classpath b/java/com.sap.sailing.gwt.ui.test/.classpath index d03a3fcb224..3f380273ffa 100644 --- a/java/com.sap.sailing.gwt.ui.test/.classpath +++ b/java/com.sap.sailing.gwt.ui.test/.classpath @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui.test/.settings/org.eclipse.jdt.core.prefs b/java/com.sap.sailing.gwt.ui.test/.settings/org.eclipse.jdt.core.prefs new file mode 100755 index 00000000000..295926d9641 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui.test/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/java/com.sap.sailing.gwt.ui.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.gwt.ui.test/META-INF/MANIFEST.MF index cd1beb793ad..d4ab683c54d 100644 --- a/java/com.sap.sailing.gwt.ui.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.gwt.ui.test/META-INF/MANIFEST.MF @@ -4,7 +4,7 @@ Bundle-Name: Test Bundle-SymbolicName: com.sap.sailing.gwt.ui.test Bundle-Version: 1.0.0.qualifier Bundle-Vendor: SAP -Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Fragment-Host: com.sap.sailing.gwt.ui Require-Bundle: com.sap.sailing.server, com.sap.sailing.expeditionconnector, diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index bad19e1dabc..2dfe39bc133 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -60,7 +60,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index 0c4449938c3..6d8dafd4065 100644 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -3,7 +3,7 @@ - + @@ -69,7 +69,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/CompactWindImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/CompactWindImpl.java index 590b96c9ade..5d1223ad852 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/CompactWindImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/CompactWindImpl.java @@ -1,5 +1,7 @@ package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl; +import java.util.logging.Logger; + import com.google.gwt.user.client.rpc.CustomFieldSerializer; import com.google.gwt.user.client.rpc.SerializationException; import com.google.gwt.user.client.rpc.SerializationStreamReader; @@ -8,46 +10,54 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreePosition; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.impl.WindImpl; -import com.sap.sailing.domain.common.tracking.impl.CompactWindImpl.CompactPosition; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl.VeryCompactPosition; +import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException; public final class CompactWindImpl { - public static final class CompactPosition_CustomFieldSerializer extends CustomFieldSerializer { + private static final Logger logger = Logger.getLogger(CompactWindImpl.class.getName()); + + public static final class CompactPosition_CustomFieldSerializer extends CustomFieldSerializer { @Override public boolean hasCustomInstantiateInstance() { return true; } @Override - public CompactPosition instantiateInstance(SerializationStreamReader streamReader) + public VeryCompactPosition instantiateInstance(SerializationStreamReader streamReader) throws SerializationException { return instantiate(streamReader); } - public static CompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException { + public static VeryCompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException { final double latDeg = streamReader.readDouble(); final double lngDeg = streamReader.readDouble(); - return (CompactPosition) new com.sap.sailing.domain.common.tracking.impl.CompactWindImpl(new WindImpl( - new DegreePosition(latDeg, lngDeg), /* timePoint */null, new KnotSpeedWithBearingImpl(0, - new DegreeBearingImpl(0)))).getPosition(); + try { + return (VeryCompactPosition) new com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl(new WindImpl( + new DegreePosition(latDeg, lngDeg), /* timePoint */null, new KnotSpeedWithBearingImpl(0, + new DegreeBearingImpl(0)))).getPosition(); + } catch (CompactionNotPossibleException e) { + logger.severe("Internal error: Cannot de-serialize compact position: "+e.getMessage()+"; throwing runtime exception"); + throw new RuntimeException(e); + } } @Override - public void deserializeInstance(SerializationStreamReader streamReader, CompactPosition instance) + public void deserializeInstance(SerializationStreamReader streamReader, VeryCompactPosition instance) throws SerializationException { deserialize(streamReader, instance); } - public static void deserialize(SerializationStreamReader streamReader, CompactPosition instance) { + public static void deserialize(SerializationStreamReader streamReader, VeryCompactPosition instance) { // handled by instantiate } @Override - public void serializeInstance(SerializationStreamWriter streamWriter, CompactPosition instance) + public void serializeInstance(SerializationStreamWriter streamWriter, VeryCompactPosition instance) throws SerializationException { serialize(streamWriter, instance); } - public static void serialize(SerializationStreamWriter streamWriter, CompactPosition instance) + public static void serialize(SerializationStreamWriter streamWriter, VeryCompactPosition instance) throws SerializationException { streamWriter.writeDouble(instance.getLatDeg()); streamWriter.writeDouble(instance.getLngDeg()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixImpl.java new file mode 100755 index 00000000000..ac837e8f190 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixImpl.java @@ -0,0 +1,52 @@ +package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl; + +import com.google.gwt.user.client.rpc.CustomFieldSerializer; +import com.google.gwt.user.client.rpc.SerializationException; +import com.google.gwt.user.client.rpc.SerializationStreamReader; +import com.google.gwt.user.client.rpc.SerializationStreamWriter; +import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixImpl.PreciseCompactPosition; + +public final class PreciseCompactGPSFixImpl { + public static final class PreciseCompactPosition_CustomFieldSerializer extends CustomFieldSerializer { + @Override + public boolean hasCustomInstantiateInstance() { + return true; + } + + @Override + public PreciseCompactPosition instantiateInstance(SerializationStreamReader streamReader) + throws SerializationException { + return instantiate(streamReader); + } + + public static PreciseCompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException { + final double latDeg = streamReader.readDouble(); + final double lngDeg = streamReader.readDouble(); + return (PreciseCompactPosition) new com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixImpl( + new DegreePosition(latDeg, lngDeg), /* timePoint */null).getPosition(); + } + + @Override + public void deserializeInstance(SerializationStreamReader streamReader, PreciseCompactPosition instance) + throws SerializationException { + deserialize(streamReader, instance); + } + + public static void deserialize(SerializationStreamReader streamReader, PreciseCompactPosition instance) { + // handled by instantiate + } + + @Override + public void serializeInstance(SerializationStreamWriter streamWriter, PreciseCompactPosition instance) + throws SerializationException { + serialize(streamWriter, instance); + } + + public static void serialize(SerializationStreamWriter streamWriter, PreciseCompactPosition instance) + throws SerializationException { + streamWriter.writeDouble(instance.getLatDeg()); + streamWriter.writeDouble(instance.getLngDeg()); + } + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixMovingImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixMovingImpl.java new file mode 100755 index 00000000000..6c3c61e43c2 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixMovingImpl.java @@ -0,0 +1,52 @@ +package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl; + +import com.google.gwt.user.client.rpc.CustomFieldSerializer; +import com.google.gwt.user.client.rpc.SerializationException; +import com.google.gwt.user.client.rpc.SerializationStreamReader; +import com.google.gwt.user.client.rpc.SerializationStreamWriter; +import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl.PreciseCompactPosition; + +public final class PreciseCompactGPSFixMovingImpl { + public static final class PreciseCompactPosition_CustomFieldSerializer extends CustomFieldSerializer { + @Override + public boolean hasCustomInstantiateInstance() { + return true; + } + + @Override + public PreciseCompactPosition instantiateInstance(SerializationStreamReader streamReader) + throws SerializationException { + return instantiate(streamReader); + } + + public static PreciseCompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException { + final double latDeg = streamReader.readDouble(); + final double lngDeg = streamReader.readDouble(); + return (PreciseCompactPosition) new com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl( + new DegreePosition(latDeg, lngDeg), /* timePoint */null, /* speedWithBearing */ null).getPosition(); + } + + @Override + public void deserializeInstance(SerializationStreamReader streamReader, PreciseCompactPosition instance) + throws SerializationException { + deserialize(streamReader, instance); + } + + public static void deserialize(SerializationStreamReader streamReader, PreciseCompactPosition instance) { + // handled by instantiate + } + + @Override + public void serializeInstance(SerializationStreamWriter streamWriter, PreciseCompactPosition instance) + throws SerializationException { + serialize(streamWriter, instance); + } + + public static void serialize(SerializationStreamWriter streamWriter, PreciseCompactPosition instance) + throws SerializationException { + streamWriter.writeDouble(instance.getLatDeg()); + streamWriter.writeDouble(instance.getLngDeg()); + } + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixImpl.java similarity index 90% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixImpl.java index 17d2493f089..87f5026329c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixImpl.java @@ -5,9 +5,9 @@ import com.google.gwt.user.client.rpc.SerializationException; import com.google.gwt.user.client.rpc.SerializationStreamReader; import com.google.gwt.user.client.rpc.SerializationStreamWriter; import com.sap.sailing.domain.common.impl.DegreePosition; -import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl.CompactPosition; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl.CompactPosition; -public final class CompactGPSFixImpl { +public final class VeryCompactGPSFixImpl { public static final class CompactPosition_CustomFieldSerializer extends CustomFieldSerializer { @Override public boolean hasCustomInstantiateInstance() { @@ -23,7 +23,7 @@ public final class CompactGPSFixImpl { public static CompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException { final double latDeg = streamReader.readDouble(); final double lngDeg = streamReader.readDouble(); - return (CompactPosition) new com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl( + return (CompactPosition) new com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixImpl( new DegreePosition(latDeg, lngDeg), /* timePoint */null).getPosition(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixMovingImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixMovingImpl.java new file mode 100755 index 00000000000..3925d573458 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixMovingImpl.java @@ -0,0 +1,64 @@ +package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.google.gwt.user.client.rpc.CustomFieldSerializer; +import com.google.gwt.user.client.rpc.SerializationException; +import com.google.gwt.user.client.rpc.SerializationStreamReader; +import com.google.gwt.user.client.rpc.SerializationStreamWriter; +import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl.VeryCompactPosition; + +public final class VeryCompactGPSFixMovingImpl { + private static final Logger logger = Logger.getLogger(VeryCompactGPSFixMovingImpl.class.getName()); + + public static final class VeryCompactPosition_CustomFieldSerializer extends CustomFieldSerializer { + @Override + public boolean hasCustomInstantiateInstance() { + return true; + } + + @Override + public VeryCompactPosition instantiateInstance(SerializationStreamReader streamReader) + throws SerializationException { + return instantiate(streamReader); + } + + public static VeryCompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException { + final double latDeg = streamReader.readDouble(); + final double lngDeg = streamReader.readDouble(); + try { + return (VeryCompactPosition) new com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl( + new DegreePosition(latDeg, lngDeg), /* timePoint */null, /* speed with bearing */ null).getPosition(); + } catch (CompactionNotPossibleException e) { + logger.log(Level.SEVERE, "Internal error: an object that was a very compact position and was serialized "+ + "couldn't be de-serialized again as such an object", e); + throw new RuntimeException(e); + } + } + + @Override + public void deserializeInstance(SerializationStreamReader streamReader, VeryCompactPosition instance) + throws SerializationException { + deserialize(streamReader, instance); + } + + public static void deserialize(SerializationStreamReader streamReader, VeryCompactPosition instance) { + // handled by instantiate + } + + @Override + public void serializeInstance(SerializationStreamWriter streamWriter, VeryCompactPosition instance) + throws SerializationException { + serialize(streamWriter, instance); + } + + public static void serialize(SerializationStreamWriter streamWriter, VeryCompactPosition instance) + throws SerializationException { + streamWriter.writeDouble(instance.getLatDeg()); + streamWriter.writeDouble(instance.getLngDeg()); + } + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/VeryCompactWindImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/VeryCompactWindImpl.java new file mode 100755 index 00000000000..68a9d961cc7 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sailing/domain/common/tracking/impl/VeryCompactWindImpl.java @@ -0,0 +1,66 @@ +package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl; + +import java.util.logging.Logger; + +import com.google.gwt.user.client.rpc.CustomFieldSerializer; +import com.google.gwt.user.client.rpc.SerializationException; +import com.google.gwt.user.client.rpc.SerializationStreamReader; +import com.google.gwt.user.client.rpc.SerializationStreamWriter; +import com.sap.sailing.domain.common.impl.DegreeBearingImpl; +import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; +import com.sap.sailing.domain.common.impl.WindImpl; +import com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl.VeryCompactPosition; +import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException; + +public final class VeryCompactWindImpl { + private static final Logger logger = Logger.getLogger(VeryCompactWindImpl.class.getName()); + + public static final class VeryCompactPosition_CustomFieldSerializer extends CustomFieldSerializer { + @Override + public boolean hasCustomInstantiateInstance() { + return true; + } + + @Override + public VeryCompactPosition instantiateInstance(SerializationStreamReader streamReader) + throws SerializationException { + return instantiate(streamReader); + } + + public static VeryCompactPosition instantiate(SerializationStreamReader streamReader) throws SerializationException { + final double latDeg = streamReader.readDouble(); + final double lngDeg = streamReader.readDouble(); + try { + return (VeryCompactPosition) new com.sap.sailing.domain.common.tracking.impl.VeryCompactWindImpl(new WindImpl( + new DegreePosition(latDeg, lngDeg), /* timePoint */null, new KnotSpeedWithBearingImpl(0, + new DegreeBearingImpl(0)))).getPosition(); + } catch (CompactionNotPossibleException e) { + logger.severe("Internal error: Cannot de-serialize compact position: "+e.getMessage()+"; throwing runtime exception"); + throw new RuntimeException(e); + } + } + + @Override + public void deserializeInstance(SerializationStreamReader streamReader, VeryCompactPosition instance) + throws SerializationException { + deserialize(streamReader, instance); + } + + public static void deserialize(SerializationStreamReader streamReader, VeryCompactPosition instance) { + // handled by instantiate + } + + @Override + public void serializeInstance(SerializationStreamWriter streamWriter, VeryCompactPosition instance) + throws SerializationException { + serialize(streamWriter, instance); + } + + public static void serialize(SerializationStreamWriter streamWriter, VeryCompactPosition instance) + throws SerializationException { + streamWriter.writeDouble(instance.getLatDeg()); + streamWriter.writeDouble(instance.getLngDeg()); + } + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/SailingLocalesAllPermutations.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/SailingLocalesAllPermutations.gwt.xml index cbc6272b1e4..b79c9c282d7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/SailingLocalesAllPermutations.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/SailingLocalesAllPermutations.gwt.xml @@ -20,5 +20,6 @@ - + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.gss index bfd4fa7fee6..ff32df6dd08 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.gss @@ -13,12 +13,14 @@ border-bottom: 1px solid #ddd; } .regattaheaderpadding { + padding-left: 4em; padding-right: 9.666667em; } .regattaheader_logo { - float: left; + position: absolute; width: 3.333333333333333em; height: 3.333333333333333em; + margin: 0.666666666666667em 0.666666666666667em 1em; text-align: center; line-height: 3.333333333333333em; background-size: contain; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.java index a51b0fc44d8..b0d8f9922f1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.java @@ -1,21 +1,21 @@ package com.sap.sailing.gwt.home.desktop.partials.regattaheader; import com.google.gwt.core.client.GWT; -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.AnchorElement; import com.google.gwt.dom.client.DivElement; +import com.google.gwt.resources.client.ImageResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.EventListener; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.common.client.BoatClassImageResolver; import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO; import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO.RaceDataInfo; import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; +import com.sap.sailing.gwt.home.shared.partials.bubble.Bubble; +import com.sap.sailing.gwt.home.shared.partials.bubble.Bubble.Direction; +import com.sap.sailing.gwt.home.shared.partials.bubble.BubbleContentBoatClass; public class RegattaHeader extends Composite { @@ -27,6 +27,8 @@ public class RegattaHeader extends Composite { @UiField RegattaHeaderResources local_res; + @UiField + AnchorElement logoUi; @UiField AnchorElement headerBodyUi; @UiField @@ -44,59 +46,34 @@ public class RegattaHeader extends Composite { public RegattaHeader(RegattaMetadataDTO regattaMetadata, boolean showStateMarker) { initWidget(uiBinder.createAndBindUi(this)); + ImageResource logo = BoatClassImageResolver.getBoatClassIconResource(regattaMetadata.getBoatClass()); + logoUi.getStyle().setBackgroundImage("url('" + logo.getSafeUri().asString() + "')"); headerBodyUi.appendChild(new RegattaHeaderBody(regattaMetadata, showStateMarker).getElement()); this.initDataIndicators(regattaMetadata.getRaceDataInfo()); - // setup click listener for icon legend bubble here, it may be replaced by setRegattaNavigation later on + // setup listeners for boat class information and data icon legend bubble here, which may be replaced later on + // by calling setRegattaNavigation and/or setRegattaRacesNavigation + addBoatClassBubble(regattaMetadata.getBoatClass()); addLegendBubble(regattaMetadata.getRaceDataInfo()); } private void addLegendBubble(final RaceDataInfo raceDataInfo) { - DOM.sinkEvents(dataIndicatorsUi, Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT); - Event.setEventListener(dataIndicatorsUi, new EventListener() { - private RegattaHeaderLegendPopup popup = null; - - @Override - public void onBrowserEvent(Event event) { - if ((event.getTypeInt() == Event.ONCLICK || event.getTypeInt() == Event.ONMOUSEOVER) - && (popup == null || !popup.isAttached())) { - popup = new RegattaHeaderLegendPopup(raceDataInfo); - popup.setVisible(false); - popup.show(); - // Pausing until the event loop is clear appears to give the browser - // sufficient time to apply CSS styling. We use the popup's offset - // width and height to calculate the display position, but those - // dimensions are not accurate until styling has been applied. - Scheduler.get().scheduleDeferred(new ScheduledCommand() { - @Override - public void execute() { - if (popup != null) { - // the arrow is ~16 pixels long - popup.setPopupPosition(dataIndicatorsUi.getAbsoluteLeft() - popup.getOffsetWidth() - 16, - RegattaHeader.this.getAbsoluteTop() + RegattaHeader.this.getOffsetHeight() / 2 - - popup.getOffsetHeight() / 2); - popup.setVisible(true); - - } - } - }); - event.preventDefault(); - event.stopPropagation(); - } - if (event.getTypeInt() == Event.ONMOUSEOUT && popup != null) { - popup.hide(); - popup = null; - event.preventDefault(); - event.stopPropagation(); - } - } - }); + RegattaHeaderBubbleContentLegend content = new RegattaHeaderBubbleContentLegend(raceDataInfo); + Bubble.DefaultPresenter presenter = new Bubble.DefaultPresenter(content, getElement(), dataIndicatorsUi, + Direction.LEFT); + presenter.registerTarget(dataIndicatorsUi); + } + private void addBoatClassBubble(final String boatClassName) { + BubbleContentBoatClass content = new BubbleContentBoatClass(boatClassName); + Bubble.DefaultPresenter presenter = new Bubble.DefaultPresenter(content, getElement(), logoUi, Direction.RIGHT); + presenter.registerTarget(logoUi); } public void setRegattaNavigation(PlaceNavigation placeNavigation) { headerArrowUi.getStyle().clearDisplay(); dataIndicatorsUi.addClassName(local_res.css().regattaheader_indicators_next_to_arrow()); + placeNavigation.configureAnchorElement(logoUi); placeNavigation.configureAnchorElement(headerBodyUi); placeNavigation.configureAnchorElement(headerArrowUi); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.ui.xml index 28eaffc704c..e8979872c35 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeader.ui.xml @@ -8,6 +8,7 @@

+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBody.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBody.java index d2a702819d4..8c5e40c31d2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBody.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBody.java @@ -4,12 +4,10 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.SpanElement; -import com.google.gwt.resources.client.ImageResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.UIObject; -import com.sap.sailing.gwt.common.client.BoatClassImageResolver; import com.sap.sailing.gwt.home.communication.event.LabelType; import com.sap.sailing.gwt.home.communication.eventview.HasRegattaMetadata.RegattaState; import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO; @@ -25,7 +23,6 @@ public class RegattaHeaderBody extends UIObject { interface RegattaHeaderBodyUiBinder extends UiBinder { } - @UiField protected DivElement logoUi; @UiField protected SpanElement nameUi; @UiField protected DivElement labelUi; @UiField protected DivElement detailsItemContainerUi; @@ -33,8 +30,6 @@ public class RegattaHeaderBody extends UIObject { public RegattaHeaderBody(RegattaMetadataDTO regattaMetadata, boolean showStateMarker) { RegattaHeaderResources.INSTANCE.css().ensureInjected(); setElement(uiBinder.createAndBindUi(this)); - ImageResource logo = BoatClassImageResolver.getBoatClassIconResource(regattaMetadata.getBoatClass()); - logoUi.getStyle().setBackgroundImage("url('" + logo.getSafeUri().asString() + "')"); nameUi.setInnerText(regattaMetadata.getDisplayName()); RegattaState state = regattaMetadata.getState(); LabelTypeUtil.renderLabelTypeOrHide(labelUi, showStateMarker ? state.getStateMarker() : LabelType.NONE); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBody.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBody.ui.xml index 0353693c42e..42627d8791d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBody.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBody.ui.xml @@ -5,7 +5,6 @@
-
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderLegendPopup.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBubbleContentLegend.java similarity index 78% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderLegendPopup.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBubbleContentLegend.java index 3d7c0c9576a..bf999f94abc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderLegendPopup.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBubbleContentLegend.java @@ -1,55 +1,55 @@ -package com.sap.sailing.gwt.home.desktop.partials.regattaheader; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.DivElement; -import com.google.gwt.uibinder.client.UiBinder; -import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.user.client.ui.PopupPanel; -import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO.RaceDataInfo; -import com.sap.sailing.gwt.ui.client.StringMessages; - -public class RegattaHeaderLegendPopup extends PopupPanel { - private static RegattaHeaderLegendPopupUiBinder uiBinder = GWT.create(RegattaHeaderLegendPopupUiBinder.class); - - interface RegattaHeaderLegendPopupUiBinder extends UiBinder { - } - - @UiField - DivElement txtGPS; - @UiField - DivElement txtWind; - @UiField - DivElement txtVideo; - @UiField - DivElement txtAudio; - - @UiField - DivElement iconGPS; - @UiField - DivElement iconWind; - @UiField - DivElement iconVideo; - @UiField - DivElement iconAudio; - - public RegattaHeaderLegendPopup(RaceDataInfo raceDataInfo) { - super(true); - setWidget(uiBinder.createAndBindUi(this)); - - txtGPS.setInnerText( - raceDataInfo.hasGPSData() ? StringMessages.INSTANCE.eventRegattaHeaderLegendGps() - : StringMessages.INSTANCE.eventRegattaHeaderLegendGpsNo()); - txtWind.setInnerText(raceDataInfo.hasWindData() ? StringMessages.INSTANCE.eventRegattaHeaderLegendWind() - : StringMessages.INSTANCE.eventRegattaHeaderLegendWindNo()); - txtVideo.setInnerText(raceDataInfo.hasVideoData() ? StringMessages.INSTANCE.eventRegattaHeaderLegendVideo() - : StringMessages.INSTANCE.eventRegattaHeaderLegendVideoNo()); - txtAudio.setInnerText(raceDataInfo.hasAudioData() ? StringMessages.INSTANCE.eventRegattaHeaderLegendAudio() - : StringMessages.INSTANCE.eventRegattaHeaderLegendAudioNo()); - - iconGPS.getStyle().setOpacity(raceDataInfo.hasGPSData() ? 1.0 : 0.15); - iconWind.getStyle().setOpacity(raceDataInfo.hasWindData() ? 1.0 : 0.15); - iconVideo.getStyle().setOpacity(raceDataInfo.hasVideoData() ? 1.0 : 0.15); - iconAudio.getStyle().setOpacity(raceDataInfo.hasAudioData() ? 1.0 : 0.15); - } -} +package com.sap.sailing.gwt.home.desktop.partials.regattaheader; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO.RaceDataInfo; +import com.sap.sailing.gwt.ui.client.StringMessages; + +public class RegattaHeaderBubbleContentLegend extends Composite { + + private static BubbleContentLegendUiBinder uiBinder = GWT.create(BubbleContentLegendUiBinder.class); + + interface BubbleContentLegendUiBinder extends UiBinder { + } + + @UiField + DivElement txtGPS; + @UiField + DivElement txtWind; + @UiField + DivElement txtVideo; + @UiField + DivElement txtAudio; + + @UiField + DivElement iconGPS; + @UiField + DivElement iconWind; + @UiField + DivElement iconVideo; + @UiField + DivElement iconAudio; + + public RegattaHeaderBubbleContentLegend(RaceDataInfo raceDataInfo) { + initWidget(uiBinder.createAndBindUi(this)); + + txtGPS.setInnerText( + raceDataInfo.hasGPSData() ? StringMessages.INSTANCE.eventRegattaHeaderLegendGps() + : StringMessages.INSTANCE.eventRegattaHeaderLegendGpsNo()); + txtWind.setInnerText(raceDataInfo.hasWindData() ? StringMessages.INSTANCE.eventRegattaHeaderLegendWind() + : StringMessages.INSTANCE.eventRegattaHeaderLegendWindNo()); + txtVideo.setInnerText(raceDataInfo.hasVideoData() ? StringMessages.INSTANCE.eventRegattaHeaderLegendVideo() + : StringMessages.INSTANCE.eventRegattaHeaderLegendVideoNo()); + txtAudio.setInnerText(raceDataInfo.hasAudioData() ? StringMessages.INSTANCE.eventRegattaHeaderLegendAudio() + : StringMessages.INSTANCE.eventRegattaHeaderLegendAudioNo()); + + iconGPS.getStyle().setOpacity(raceDataInfo.hasGPSData() ? 1.0 : 0.15); + iconWind.getStyle().setOpacity(raceDataInfo.hasWindData() ? 1.0 : 0.15); + iconVideo.getStyle().setOpacity(raceDataInfo.hasVideoData() ? 1.0 : 0.15); + iconAudio.getStyle().setOpacity(raceDataInfo.hasAudioData() ? 1.0 : 0.15); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBubbleContentLegend.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBubbleContentLegend.ui.xml new file mode 100644 index 00000000000..40f156ed706 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderBubbleContentLegend.ui.xml @@ -0,0 +1,50 @@ + + + + + .iconGPS, .iconWind, .iconVideo, .iconAudio { + line-height: 1.5em; + position: relative; + height:1.666666666666667rem; + display: inline-block; + padding-left: 2.333333333333333em; + background-size: 1.666666666666667rem 1.666666666666667rem; + background-position: left bottom; + background-repeat: no-repeat; + } + .iconGPS { + background-image:url('images/home/raw_gps_fixes.png'); + } + .iconWind { + margin-left: 0.666666666666667em; + background-image:url('images/home/icon-wind.png'); + border-left: 1px solid #ccc; + } + .iconVideo { + background-image:url('images/home/icon-video.png'); + padding-top: 0.277777777777778em; + } + .iconAudio { + margin-left: 0.666666666666667em; + background-image:url('images/home/icon-audio.png'); + border-left: 1px solid #ccc; + padding-top: 0.277777777777778em; + } + + + + + + + + + + + + + + + +
+
+
\ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderLegendPopup.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderLegendPopup.ui.xml deleted file mode 100644 index 6f571d0af0e..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/regattaheader/RegattaHeaderLegendPopup.ui.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - .iconGPS, .iconWind, .iconVideo, .iconAudio{ - line-height: 1.5em; - position: relative; - height:1.666666666666667rem; - display: inline-block; - padding-left: 2.333333333333333em; - background-size: 1.666666666666667rem 1.666666666666667rem; - background-position: left bottom; - background-repeat: no-repeat; - } - .iconGPS { - background-image:url('images/home/raw_gps_fixes.png'); - } - .iconWind { - margin-left: 0.666666666666667em; - background-image:url('images/home/icon-wind.png'); - border-left: 1px solid #ccc; - } - .iconVideo { - background-image:url('images/home/icon-video.png'); - padding-top: 0.277777777777778em; - } - .iconAudio { - margin-left: 0.666666666666667em; - background-image:url('images/home/icon-audio.png'); - border-left: 1px solid #ccc; - padding-top: 0.277777777777778em; - } - .legend{ - padding: .2em; - border-radius: .277777777777778em; - width:100%; - background-color:white; - border: 1px solid #ccc; - } - .legend:after, .legend:before { - left: 100%; - top: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - // pointer-events: none; - } - - .legend:after { - border-color: rgba(255, 255, 255, 0); - border-left-color: #ffffff; - border-width: .55em; - margin-top: -0.55em; - margin-left: -2px; - } - .legend:before { - border-color: rgba(204, 204, 204, 0); - border-left-color: #ccc; - border-width: 0.55em; - margin-top: -0.55em; - } - - - - - - - - - - - - - - - -
-
-
\ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/partials/eventsteps/EventSteps.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/partials/eventsteps/EventSteps.java index 98147f02cdf..53cc73e4a0e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/partials/eventsteps/EventSteps.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/partials/eventsteps/EventSteps.java @@ -1,15 +1,17 @@ package com.sap.sailing.gwt.home.mobile.partials.eventsteps; import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ImageResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; +import com.sap.sailing.gwt.common.client.BoatClassImageResolver; +import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO; import com.sap.sailing.gwt.home.communication.regatta.RegattaProgressSeriesDTO; import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO; import com.sap.sailing.gwt.home.mobile.partials.section.MobileSection; import com.sap.sailing.gwt.home.mobile.partials.sectionHeader.SectionHeaderContent; import com.sap.sailing.gwt.home.shared.refresh.RefreshableWidget; -import com.sap.sailing.gwt.ui.client.StringMessages; public class EventSteps extends Composite implements RefreshableWidget { @@ -21,11 +23,14 @@ public class EventSteps extends Composite implements RefreshableWidget { + } + + @UiField + DivElement boatClassNameUi; + + /** + * Creates a new {@link BubbleContentBoatClass} instance showing the given boat class name. + * + * @param boatClassName + */ + public BubbleContentBoatClass(String boatClassName) { + initWidget(uiBinder.createAndBindUi(this)); + boatClassNameUi.setInnerText(boatClassName); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/bubble/BubbleContentBoatClass.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/bubble/BubbleContentBoatClass.ui.xml new file mode 100644 index 00000000000..4ca16f5c86b --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/bubble/BubbleContentBoatClass.ui.xml @@ -0,0 +1,14 @@ + + + + + + .titleText { + font-weight: bold; + } + + +
+
+
+
\ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java index ffbfc751e8c..5d543cae512 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java @@ -515,47 +515,68 @@ public abstract class AbstractTrackedRacesListComposite extends SimplePanel * @param regattas */ @Override - public void fillRegattas(Iterable regattas) { - makeControlsReactToFillRegattas(regattas); - if (Util.isEmpty(regattas)) { - raceTable.setVisible(false); - noTrackedRacesLabel.setVisible(true); - } else { - raceTable.setVisible(true); - noTrackedRacesLabel.setVisible(false); - } - List newAllRaces = new ArrayList(); - List newAllRegattas = new ArrayList(); - List regattaNames = new ArrayList<>(); - for (RegattaDTO regatta : regattas) { - newAllRegattas.add(regatta); - for (RaceDTO race : regatta.races) { - if (race != null) { - if (raceIsToBeAddedToList(race)) { - //We need only those regatta names which are available - //at tracking table - if (!regattaNames.contains(regatta.getName())) { - regattaNames.add(regatta.getName()); - } - newAllRaces.add(race); - } - } - } - } - - listBoxRegattas.clear(); - listBoxRegattas.addItem(stringMessages.all(), ""); - regattaNames.stream().sorted().forEach(regatta->listBoxRegattas.addItem(regatta, regatta)); - allRaces = newAllRaces; - filterablePanelRaces.updateAll(allRaces); - } - + public void fillRegattas(Iterable regattas) { + makeControlsReactToFillRegattas(regattas); + displayRaceTableUI(regattas); + final List newAllRaces = new ArrayList(); + final List regattaNames = new ArrayList<>(); + for (RegattaDTO regatta : regattas) { + for (RaceDTO race : regatta.races) { + if (race != null) { + if (raceIsToBeAddedToList(race)) { + // We need only those regatta names which are available + // at tracking table + if (!regattaNames.contains(regatta.getName())) { + regattaNames.add(regatta.getName()); + } + newAllRaces.add(race); + } + } + } + } + refreshListBoxRegattas(regattaNames); + allRaces = newAllRaces; + filterablePanelRaces.updateAll(allRaces); + } + + private void refreshListBoxRegattas(List regattaNames) { + final String lastSelectedRegattaName = listBoxRegattas.getSelectedValue(); + listBoxRegattas.clear(); + listBoxRegattas.addItem(stringMessages.all(), ""); + regattaNames.stream().sorted().forEach(regatta -> listBoxRegattas.addItem(regatta, regatta)); + restoreListBoxRegattasSelection(lastSelectedRegattaName); + } + + private void restoreListBoxRegattasSelection(String lastSelectedRegattaName) { + for (int i = 0; i < listBoxRegattas.getItemCount(); i++) { + if (listBoxRegattas.getValue(i).equals(lastSelectedRegattaName)) { + listBoxRegattas.setSelectedIndex(i); + break; + } + } + } + + private void displayRaceTableUI(Iterable regattas) { + if (Util.isEmpty(regattas)) { + hideRaceTable(); + } else { + showRaceTable(); + } + } + + private void showRaceTable() { + raceTable.setVisible(true); + noTrackedRacesLabel.setVisible(false); + } + + private void hideRaceTable() { + raceTable.setVisible(false); + noTrackedRacesLabel.setVisible(true); + } + /** * Allows applying some sort of filter to the process of adding races. Defaults to true in standard implementation. * Override for custom behavior - * - * @param race - * @return */ protected boolean raceIsToBeAddedToList(RaceDTO race) { return true; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java index f45175e8c0d..28eb2329c9f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java @@ -260,7 +260,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements }, getStringMessages().replication(), Permission.MANAGE_REPLICATION); final MasterDataImportPanel masterDataImportPanel = new MasterDataImportPanel(getStringMessages(), sailingService, - this, eventManagementPanel, this, this); + this, eventManagementPanel, this, this, mediaPanel); panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel(masterDataImportPanel), getStringMessages().masterDataImportPanel(), Permission.MANAGE_MASTERDATA_IMPORT); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java index 5310d6e6607..9166d9f73a8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java @@ -40,6 +40,7 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.media.MediaTrack; import com.sap.sailing.domain.common.media.MediaUtil; import com.sap.sailing.gwt.ui.client.MediaServiceAsync; +import com.sap.sailing.gwt.ui.client.MediaTracksRefresher; import com.sap.sailing.gwt.ui.client.RegattaRefresher; import com.sap.sailing.gwt.ui.client.RegattasDisplayer; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; @@ -64,7 +65,7 @@ import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; * @author D047974 * */ -public class MediaPanel extends FlowPanel { +public class MediaPanel extends FlowPanel implements MediaTracksRefresher { private final SailingServiceAsync sailingService; private final LabeledAbstractFilterablePanel filterableMediaTracks; @@ -138,7 +139,8 @@ public class MediaPanel extends FlowPanel { buttonAndFilterPanel.add(filterableMediaTracks); } - protected void loadMediaTracks() { + @Override + public void loadMediaTracks() { mediaTrackListDataProvider.getList().clear(); mediaService.getAllMediaTracks(new AsyncCallback>() { @Override @@ -153,8 +155,6 @@ public class MediaPanel extends FlowPanel { mediaTrackListDataProvider.refresh(); } }); - - } private void createMediaTracksTable() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/MediaTracksRefresher.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/MediaTracksRefresher.java new file mode 100755 index 00000000000..3fc28060359 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/MediaTracksRefresher.java @@ -0,0 +1,5 @@ +package com.sap.sailing.gwt.ui.client; + +public interface MediaTracksRefresher { + void loadMediaTracks(); +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 7f32068f28e..634c6400eb7 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -45,6 +45,7 @@ import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRa import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException; import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException; import com.sap.sailing.domain.common.racelog.tracking.TransformationException; +import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl.PreciseCompactPosition; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter; import com.sap.sailing.domain.tracking.TrackedRace; @@ -668,5 +669,5 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS Map, Pair> getTrackingTimes(Collection> raceColumnsAndFleets); - Pair makePersonDTOSerializableAndDeserializableDummy(PersonDTO dummy, CountryCode ccDummy); + Pair serializationDummy(PersonDTO dummy, CountryCode ccDummy, PreciseCompactPosition preciseCompactPosition); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 52642309e93..d966598d23a 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -36,6 +36,7 @@ import com.sap.sailing.domain.common.dto.RaceColumnInSeriesDTO; import com.sap.sailing.domain.common.dto.RaceDTO; import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO; import com.sap.sailing.domain.common.racelog.RacingProcedureType; +import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl.PreciseCompactPosition; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.gwt.ui.adminconsole.RaceLogSetTrackingTimesDTO; import com.sap.sailing.gwt.ui.client.shared.charts.MarkPositionService.MarkTrackDTO; @@ -816,6 +817,6 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan void getTrackingTimes(Collection> raceColumnsAndFleets, AsyncCallback, Pair>> asyncCallback); - void makePersonDTOSerializableAndDeserializableDummy(PersonDTO dummy, CountryCode ccDummy, - AsyncCallback> callback); + void serializationDummy(PersonDTO dummy, CountryCode ccDummy, + PreciseCompactPosition preciseCompactPosition, AsyncCallback> callback); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index e39cb2e1322..444c2b12f82 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -435,6 +435,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String scoringSchemeHighPointEssOverall12Description(); String scoringSchemeHighPointFirstGetsTwelveOrEight(); String scoringSchemeHighPointFirstGetsTwelveOrEightDescription(); + String scoringSchemeHighPointFirstGetsTwelveOrEight2017(); + String scoringSchemeHighPointFirstGetsTwelveOrEight2017Description(); String scoringSystem(); String createFlexibleLeaderboard(); String createRegattaLeaderboard(); @@ -771,7 +773,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String regattaDefinesResultDiscardingRules(); String startsWithZeroScore(); String masterDataImportPanel(); - String importSuccess(int leaderboardGroups, int leaderboards, int events, int regattas); + String importSuccess(int leaderboardGroups, int leaderboards, int events, int regattas, int mediaTracksImported); String importSuccessOverwriteInfo(); String regattaOverviewConfiguration(); String firstRaceIsNonDiscardableCarryForward(); @@ -1446,7 +1448,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String shownDecimals(); String openFullscreenView(); String closeFullscreenView(); - String progress(); String videosCount(@PluralCount(DefaultRule_1_0n.class) int count); String photosCount(@PluralCount(DefaultRule_1_0n.class) int count); String eventsHaveTakenPlace(@PluralCount(DefaultRule_1_0n.class) int eventCount); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 8cfb422cf35..65080c78e41 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -452,6 +452,8 @@ scoringSchemeHighPointFirstGetsTenOrEight=High Point, winner gets 10 points (or scoringSchemeHighPointFirstGetsTenOrEightDescription=Score in points. Winner scores 10 points, 2nd - 9 points, .... A tie is broken in favour of the competitor having won most races, if tie remains then tie is broken by the rank in the last race scored. scoringSchemeHighPointFirstGetsTwelveOrEight=High Point, winner gets 12 points (or 8) scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored. +scoringSchemeHighPointFirstGetsTwelveOrEight2017=High Point ESS 2017, winner gets 12 points (or 8) +scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored. scoringSystem=Scoring system createFlexibleLeaderboard=Create flexible leaderboard createRegattaLeaderboard=Create regatta leaderboard @@ -750,7 +752,7 @@ addSeries=Add series regattaDefinesResultDiscardingRules=Regatta defines result discarding rules startsWithZeroScore=Series starts with zero score masterDataImportPanel=Master Data Import -importSuccess=Success\nCreated {0} leaderboard group(s) and {1} leaderboard(s) and {2} event(s) and {3} regatta(s). +importSuccess=Success\nCreated {0} leaderboard group(s) and {1} leaderboard(s) and {2} event(s) and {3} regatta(s) and {4} media tracks. importSuccessOverwriteInfo=Had to overwrite the following regattas, you will need to retrack their races: regattaOverviewConfiguration=Regatta Overview Configuration firstRaceIsNonDiscardableCarryForward=Starts with non-discardable carry-forward @@ -1352,7 +1354,7 @@ orcPerformanceCurveRankingMetric=ORC Performance Curve timeOnTimeAndDistanceRankingMetric=Time-on-Time/Time-on-Distance oneDesignRankingMetricDescription=One-Design: First across the line wins;\nin-race ranks based on windward positions (upwind/downwind) or along-course position (reaching) orcPerformanceCurveRankingMetricDescription=ORC Performance Curve: Sophisticated handicapping scheme that awards time allowances based on a VPP/polar assuming pre-defined legs'' angles to the wind;\nbased on these allowances, an "implied wind" is calculated which is the basis for ranking.\nImplied wind can be calculated at any time in the race and is therefore the basis for in-race ranking. -timeOnTimeAndDistanceRankingMetricDescription=Time-on-Time / Time-on-Distance: Final ranking by calculated time;\ntime is calculated by optionally applying a factor to the actual time (defaulting to 1.0)\nand subtracting an allowance in seconds per nautical mile,\napplied to the course length.\nIn-race ranks based on expected arrival at fastest boat's current position\nassuming current leg's average VMG/VMC. +timeOnTimeAndDistanceRankingMetricDescription=Time-on-Time / Time-on-Distance: Final ranking by calculated time;\ntime is calculated by optionally applying a factor to the actual time (defaulting to 1.0)\nand subtracting an allowance in seconds per nautical mile,\napplied to the course length.\nIn-race ranks based on expected arrival at fastest boat''s current position\nassuming current leg''s average VMG/VMC. timeOnTimeFactor=ToT Factor timeOnDistanceAllowanceInSecondsPerNauticalMile=ToD Allowance timeOnTimeFactorTooltip=Time-on-Time factor; actual time is multiplied with this factor in calculated time formula @@ -1414,7 +1416,6 @@ cantDisplayDataOfType=Can''t display data of type {0} shownDecimals=Shown Decimals openFullscreenView=Open fullscreen view closeFullscreenView=Close fullscreen view -progress=Progress videosCount={0,number} videos videosCount[one]={0,number} video photosCount={0,number} photos diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 5d663e2a901..6b8c149bc2f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -353,7 +353,7 @@ showWindSpeedSeries=Daten für Windgeschwindigkeit zeigen showWindDirectionSeries=Daten für Windrichtung zeigen fleet=Flotte boatClass=Bootsklasse -setDelayToLive=Verzögerung zu 'Live' setzen +setDelayToLive=Verzögerung zu ''Live'' setzen pleaseEnterNonEmptyVenue=Bitte geben sie einen Veranstaltungsort ein. pleaseEnterStartAndEndDate=Bitte geben Sie ein Start- und Endedatum an. startDateMustBeforeEndDate=Das Startdatum muß vor dem Endedatum liegen. @@ -745,7 +745,7 @@ addSeries=Serie hinzufügen regattaDefinesResultDiscardingRules=Streichergebnisse werden von der Regatta festgelegt startsWithZeroScore=Serie beginnt mit auf 0 gesetzten Ergebnissen masterDataImportPanel=Master Data Import -importSuccess=Erfolg\nEs wurden {0} leaderboard group(s) und {1} leaderboard(s) und {2} event(s) und {3} regatta(s) erstellt. +importSuccess=Erfolg\nEs wurden {0} Ranglistengruppe(n) und {1} Rangliste(n) und {2} Veranstaltung(en) und {3} Regatten sowie {4} Medienbeiträge erstellt. importSuccessOverwriteInfo=Die folgenden Regatten wurden überschrieben; ihre Rennen müssen neu getrackt werden: addReplicationMaster=Verbindung mit Master herstellen connect=Verbinden @@ -956,7 +956,7 @@ rrs26Start=RRS26 Start sailingWorldCupStart=Sailing World Cup Start setConfiguration=Aktiviere Konfiguration classFlag=Klassenflagge -classFlagHelpText=Setzt die Klassenflagge für {0}. Wähle 'Nicht überschreiben' um die Standardflagge der Rennart zu wählen. +classFlagHelpText=Setzt die Klassenflagge für {0}. Wähle ''Nicht überschreiben'' um die Standardflagge der Rennart zu wählen. individualRecallHelpText=Wenn aktiviert, ermöglicht dies dem Race Officer, Einzelrückruf anzuwenden. resultEntryHelpText=Wenn aktiviert, ermöglicht dies dem Race Officer, Ergebnisse während und nach der Beendigungsphase zu erfassen. startmodeFlags=Startmodus-Flaggen @@ -1398,7 +1398,6 @@ cantDisplayDataOfType=Daten des Typs {0} können nicht dargestellt werden shownDecimals=Angezeigte Nachkommastellen openFullscreenView=Vollbildansicht öffnen closeFullscreenView=Vollbildansicht schließen -progress=Fortschritt videosCount={0,number} Videos videosCount[one]={0,number} Video photosCount={0,number} Bilder @@ -1474,6 +1473,8 @@ confirmLosingCompetitorEditsWhenTogglingLogBasedView=Damit werden alle aktuellen removalOfMarkDisabledMayBeUsedInRaces=Löschung deaktiviert, Bahnmarke wird in folgenden anderen Wettfahrten benutzt: {0} scoringSchemeHighPointFirstGetsTwelveOrEight=High-Point System 12 Punkte scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Scores als Punkte. Der Gewinner bekommt 12 Punkte. +scoringSchemeHighPointFirstGetsTwelveOrEight2017=High-Point System 12 Punkte ESS2017 +scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Scores als Punkte. Der Gewinner bekommt 12 Punkte. scoringSchemeHighPointEssOverall12=High Point System ESS Gesamtwertung (12) scoringSchemeHighPointEssOverall12Description=High Point System, der Gewinner eines Acts erhält 12 Punkte, der Zweite 11 und so weiter. pleaseCreateAtLeastOneMappingBy=Bitte erstellen Sie mindestens eine Zuordnung, indem Sie zunächst einen Track auf der linken Seite und anschließend einen Teilnehmer oder eine Tonne auf der rechten Seite auswählen diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties index 988518cb440..1876f8dffb8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties @@ -748,7 +748,7 @@ addSeries=Añadir serie regattaDefinesResultDiscardingRules=La regata define reglas de rechazo de resultado startsWithZeroScore=La serie empieza con puntuación cero masterDataImportPanel=Importación de datos maestros -importSuccess=Grupos de tablas de clasificación{0} creadas\n con éxito {1} y {2} eventos y {3} regatas. +importSuccess=Grupos de tablas de clasificación{0} creadas\n con éxito {1} y {2} eventos y {3} regatas. TODO {4} importSuccessOverwriteInfo=Se han tenido que sobrescribir las regatas siguientes, deberá volver a rastrear sus carreras. regattaOverviewConfiguration=Configuración del resumen de regata firstRaceIsNonDiscardableCarryForward=Empieza con no descartables seguir adelante diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties index c0906f47ae7..6ad08f5058e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties @@ -11,11 +11,11 @@ listRaces=Lister courses listRegattas=Lister régates wind=Vent maneuverType=Manœuvre -windPanelLabel=Ceci est le panneau des mesures du vent, vide pour l'instant. +windPanelLabel=Ceci est le panneau des mesures du vent, vide pour l''instant. refresh=Actualiser remove=Supprimer windSource=Source du vent -dampeningInterval=Intervalle d'atténuation +dampeningInterval=Intervalle d''atténuation map=Carte race=Course races=Courses @@ -31,7 +31,7 @@ timeDelay=Décalage timeDelayHelp=Laissez vide pour effectuer la relecture à un moment de votre choix. Saisissez des secondes de décalage avant le flux des données en direct (p.ex. "60" pour une minute ou "0" pour "Sans décalage"). speedInKnots=Vitesse (nd) fromDeg=De (°) -noRacesYet=Aucune course pour l'instant. +noRacesYet=Aucune course pour l''instant. total=Σ carry=Cumulé competitor=Concurrent @@ -53,8 +53,8 @@ pleaseEnterAName=Saisissez un nom. pleaseEnterABoatClass=Saisissez une catégorie de bateau. discardRacesFromHowManyStartedRacesOn=Éliminez une course de plus en commençant au nombre de courses déjà lancées. leaderboardWithThisNameAlreadyExists=Un palmarès de ce nom existe déjà. -discardThresholdsMustBeNumeric=Les seuils d'élimination doivent être numériques. -discardThresholdsMustBeAscending=Les seuils d'élimination doivent être ascendants. +discardThresholdsMustBeNumeric=Les seuils d''élimination doivent être numériques. +discardThresholdsMustBeAscending=Les seuils d''élimination doivent être ascendants. discarding=Élimination en cours startingFromNumberOfRaces=Début au nombre de courses renameLeaderboard=Renommer palmarès @@ -89,17 +89,17 @@ selectAtLeastOneLegDetail=Sélectionnez au moins un détail de portion de parcou currentSpeedOverGroundInKnots=Vf currentSpeedOverGroundInKnotsTooltip=La vitesse fond actuelle. estimatedTimeToNextWaypointInSeconds=TEA -estimatedTimeToNextWaypointInSecondsTooltip=Temps estimé avant l'arrivée dont aura besoin le concurrent pour atteindre le prochain point de cheminement, basé sur le compromis Cap/Vitesse (VMG) actuel du concurrent, en prenant compte de la direction réelle du vent. +estimatedTimeToNextWaypointInSecondsTooltip=Temps estimé avant l''arrivée dont aura besoin le concurrent pour atteindre le prochain point de cheminement, basé sur le compromis Cap/Vitesse (VMG) actuel du concurrent, en prenant compte de la direction réelle du vent. gapToLeaderInSeconds=Écart par rapport au concurrent en tête -gapToLeaderInSecondsTooltip=Estime l'heure d'arrivée (calculée) à la position actuelle du bateau en tête de la course.\nLe calcul est basé sur le compromis Cap/Vitesse (VMG) moyen de la portion du parcours actuelle, et une performance égale à celle du concurrent en tête de la course pour les portions de parcours suivantes.\nL'écart indique de combien temps plus tôt le concurrent aurait dû arriver là où il/elle se trouve actuellement\nafin de pouvoir prétendre à la même place que le concurrent en tête de la course, à l'arrivée projetée à la position actuelle du bateau en tête. +gapToLeaderInSecondsTooltip=Estime l''heure d''arrivée (calculée) à la position actuelle du bateau en tête de la course.\nLe calcul est basé sur le compromis Cap/Vitesse (VMG) moyen de la portion du parcours actuelle, et une performance égale à celle du concurrent en tête de la course pour les portions de parcours suivantes.\nL''écart indique de combien temps plus tôt le concurrent aurait dû arriver là où il/elle se trouve actuellement\nafin de pouvoir prétendre à la même place que le concurrent en tête de la course, à l''arrivée projetée à la position actuelle du bateau en tête. velocityMadeGoodInKnots=VMG velocityMadeGoodInKnotsTooltip=Le compromis Cap/Vitesse (Velocity Made Good) correspond à la vitesse au vent/sous le vent pour portions de parcours dans le lit du vent/à vent arrière, respectivement, ou à la vitesse de parcours pour atteindre une portion de parcours. windwardDistanceToGoInMeters=Distance au vent/sous le vent restante -windwardDistanceToGoInMetersTooltip=Distance au vent/sous le vent de la position actuelle du concurrent jusqu'à la fin de cette portion de parcours pour les portions dans le lit du vent/à vent arrière, respectivement, ou la distance de parcours pour atteindre une portion de parcours. +windwardDistanceToGoInMetersTooltip=Distance au vent/sous le vent de la position actuelle du concurrent jusqu''à la fin de cette portion de parcours pour les portions dans le lit du vent/à vent arrière, respectivement, ou la distance de parcours pour atteindre une portion de parcours. windwardDistanceToCompetitorFarthestAheadInMeters=Écart -windwardDistanceToCompetitorFarthestAheadInMetersTooltip=Distance au vent/sous le vent entre le concurrent et celui en tête de la course pour les portions de parcours dans le lit du vent/à vent arrière, respectivement, ou la distance de parcours pour atteindre une portion de parcours.\nNotez que le concurrent en tête n'est pas forcément premier de la course si un classement prenant en compte les difficultés est en vigueur. +windwardDistanceToCompetitorFarthestAheadInMetersTooltip=Distance au vent/sous le vent entre le concurrent et celui en tête de la course pour les portions de parcours dans le lit du vent/à vent arrière, respectivement, ou la distance de parcours pour atteindre une portion de parcours.\nNotez que le concurrent en tête n''est pas forcément premier de la course si un classement prenant en compte les difficultés est en vigueur. name=Nom -leaveEmptyForDefault=Laissez vide pour que la valeur par défaut s'applique. +leaveEmptyForDefault=Laissez vide pour que la valeur par défaut s''applique. trackNewEvent=Suivre une nouvelle manifestation trackableRaces=Courses disponibles pour suivi trackWind=Suivre le vent @@ -129,7 +129,7 @@ storedPort=Port données stockées liveUri=URI en direct storedUri=URI stockée eventsConnectedTo=Manifestations actuellement suivies -hostname=Nom de l'hôte +hostname=Nom de l''hôte declinationCheckbox=Corriger la direction du vent par déclinaison raceStartTrackingColumn=Suivi lancé pauseAutomaticRefresh=Arrêter Actualisation automatique @@ -137,10 +137,10 @@ autoRefresh=Actualiser automatiquement delayInSeconds=Décalage (s) delayBetweenAutoAdvances=Décalage entre mises à jour automatiques en secondes : delayMustBeNonNegative=Le décalage doit être supérieur à zéro. -chooseUpdateIntervalOfAtLeastOneSecond=Sélectionnez un intervalle de mise à jour d'au moins une seconde. +chooseUpdateIntervalOfAtLeastOneSecond=Sélectionnez un intervalle de mise à jour d''au moins une seconde. errorSettingWindForRace=Erreur lors de la définition du vent pour la course -errorFetchingWindInformationForRace=Erreur lors de l'accès aux données de vent pour la course -errorWhileTryingToSetWindSourceForRace=Erreur lors de la tentative d'activation de l'indicateur "Vent de début : au vent" +errorFetchingWindInformationForRace=Erreur lors de l''accès aux données de vent pour la course +errorWhileTryingToSetWindSourceForRace=Erreur lors de la tentative d''activation de l''indicateur "Vent de début : au vent" inEvent=dans la manifestation to=à toSide=à @@ -154,7 +154,7 @@ columnMoveDown=Arrière port=À bâbord raceStartTimeColumn=Course lancée showOnlySelectedCompetitors=Afficher uniquement concurrents sélectionnés -showSelectedCompetitorsInfo=Afficher carré d'infos pour concurrents sélectionnés +showSelectedCompetitorsInfo=Afficher carré d''infos pour concurrents sélectionnés tailLength=Longueur du parcours effectué (s) selectedRaces=Quelles courses souhaitez-vous afficher ? lengthInSeconds=Longueur (s) @@ -163,15 +163,15 @@ numberOfManeuvers=Manœuvres numberOfManeuversTooltip=Le nombre de manœuvres effectuées dans cette portion du parcours. numberOfManeuversInRaceTooltip=Le nombre de manœuvres effectuées dans cette course. tacks=Virements -jibes=Changements d'amure +jibes=Changements d''amure penaltyCircles=Tours de pénalité medalRaceIsNull=Valeur de course à la médaille non autorisée configuration=Configuration maneuverTypes=Manœuvres chooseChart=Sélectionner graphique distanceTraveled=Distance parcourue -distanceTraveledTooltip=Distance naviguée du début de la portion de parcours jusqu'à sa fin\nou jusqu'à l'heure actuelle, si la portion de parcours n'est pas terminée. -raceDistanceTraveledTooltip=Distance naviguée du début de la course jusqu'à sa fin\nou jusqu'à l'heure actuelle, si la course n'est pas terminée. +distanceTraveledTooltip=Distance naviguée du début de la portion de parcours jusqu''à sa fin\nou jusqu''à l''heure actuelle, si la portion de parcours n''est pas terminée. +raceDistanceTraveledTooltip=Distance naviguée du début de la course jusqu''à sa fin\nou jusqu''à l''heure actuelle, si la course n''est pas terminée. velocityMadeGoodLong=Compromis Cap/Vitesse (VMG) speedOverGroundLong=Vitesse fond gapToLeaderLong=Écart par rapport au concurrent en tête @@ -198,8 +198,8 @@ headUp=Lofer bearAway=Abattre tack=Virer tackTooltip=Le nombre de virements effectués dans cette course. -jibe=Changement d'amure -jibeTooltip=Le nombre de changements d'amure effectués dans cette course. +jibe=Changement d''amure +jibeTooltip=Le nombre de changements d''amure effectués dans cette course. penaltyCircle=Tour de pénalité penaltyCircleTooltip=Le nombre de tours de pénalité effectués dans cette course. markPassing=Passage de marque @@ -272,11 +272,11 @@ detailsOfLeaderboardGroup=Détails du groupe de palmarès edit=Modifier save=Enregistrer abort=Abandonner -noLeaderboardGroupWithNameFound=Aucun groupe de palmarès ayant pour nom {0} n'a été trouvé. +noLeaderboardGroupWithNameFound=Aucun groupe de palmarès ayant pour nom {0} n''a été trouvé. overview=Synthèse welcomeToSailingAnalytics=Bienvenue dans SAP Sailing Analytics -welcomeToSailingAnalyticsBody=Grâce aux solutions SAP, l'action sur l'eau est à portée de main pour les amateurs de la voile, comme jamais auparavant.\ Le palmarès actualisé en direct ajoute un vrai plus, avec des classements, vitesses de bateaux et marges de victoire en temps réel. Avec SAP, suivez chaque course et ne ratez aucune manœuvre de passage.\ Regarder les compétitions de voile en direct où que vous soyez devient un jeu d'enfant. -home=Page d'accueil +welcomeToSailingAnalyticsBody=Grâce aux solutions SAP, l''action sur l''eau est à portée de main pour les amateurs de la voile, comme jamais auparavant.\ Le palmarès actualisé en direct ajoute un vrai plus, avec des classements, vitesses de bateaux et marges de victoire en temps réel. Avec SAP, suivez chaque course et ne ratez aucune manœuvre de passage.\ Regarder les compétitions de voile en direct où que vous soyez devient un jeu d''enfant. +home=Page d''accueil clickAndDragToZoomIn=Cliquez et faites glisser dans la zone de traçage pour zoomer. windSpeed=Vitesse du vent (en nds) allTimesInUTC=Toutes les heures au format UTC @@ -292,10 +292,10 @@ autoZoomToTails=Parcours effectués autoZoomSelectedCompetitors=Zoomer uniquement sur les concurrents sélectionnés bearing=Direction zoom=Zoom -stepSizeMustBeGreaterThanNull=La taille de l'étape doit être supérieure à 0. -stepSizeInSeconds=Taille de l'étape en secondes -refreshInterval=Intervalle(s) d'actualisation -refreshIntervalMustBeGreaterThanXSeconds=L'intervalle d'actualisation doit être supérieur à {0} secondes. +stepSizeMustBeGreaterThanNull=La taille de l''étape doit être supérieure à 0. +stepSizeInSeconds=Taille de l''étape en secondes +refreshInterval=Intervalle(s) d''actualisation +refreshIntervalMustBeGreaterThanXSeconds=L''intervalle d''actualisation doit être supérieur à {0} secondes. competitorCharts=Graphique de concurrents selectAtLeastOneCompetitor=Pour afficher les graphiques des concurrents, sélectionnez au moins un concurrent. selectAtLeastOneCompetitorForInvitation=Pour envoyer une invitation par e-mail, sélectionnez au moins un concurrent. @@ -314,7 +314,7 @@ trackBasedEstimationWindSourceTypeName=Estimation windSensorWindSourceTypeName=Mesuré webWindSourceTypeName=Manuel raceCommitteeWindSourceTypeName=Comité de course -clickChartToSetTime=Cliquez sur le graphique pour définir l'heure. +clickChartToSetTime=Cliquez sur le graphique pour définir l''heure. position=Position windSourcesUsed=Sources de vent utilisées errorTryingToUpdateWindSourcesToExclude=Erreur lors de la tentative de mise à jour des sources de vent à exclure pour la course {0} : {1} @@ -328,21 +328,21 @@ degreesBoatToTheWind=Angle par rapport au vent racesInLeaderboard=Courses dans le palmarès leaderboardsInGroup=Palmarès dans le groupe replication=Réplication -errorFetchingReplicaData=Erreur lors de l'accès aux données de réplicas : {0} +errorFetchingReplicaData=Erreur lors de l''accès aux données de réplicas : {0} averageAbsoluteCrossTrackErrorInMeters=∅ XTE -averageAbsoluteCrossTrackErrorInMetersTooltip=Écart de route (XTE) moyen par rapport à l'arc de cercle reliant le début d'une portion de parcours à la fin d'une portion de parcours. +averageAbsoluteCrossTrackErrorInMetersTooltip=Écart de route (XTE) moyen par rapport à l''arc de cercle reliant le début d''une portion de parcours à la fin d''une portion de parcours. averageSignedCrossTrackErrorInMeters=∅ XTE +/- averageSignedCrossTrackErrorInMetersTooltip=Position moyenne dans la course sous forme de distance enregistrée par rapport à la layline de la course. 0 signifie que vous vous trouvez sur la layline. Les valeurs négatives indiquent que vous avez dévié de votre route sur la gauche. Les valeurs positives indiquent que vous avez dévié de votre route sur la droite. -raceAverageAbsoluteCrossTrackErrorInMetersTooltip=Écart de route moyen absolu par rapport aux arcs de cercle reliant le début d'une portion de parcours à la fin d'une portion de parcours pour toutes les portions de parcours dans le lit du vent de cette course, en ignorant de quel côté de la layline de la course le concurrent se trouve. -raceAverageSignedCrossTrackErrorInMetersTooltip=Écart de route moyen enregistré par rapport aux arcs de cercle reliant le début d'une portion de parcours à la fin d'une portion de parcours pour toutes les portions de parcours dans le lit du vent de cette course. Les valeurs négatives indiquent que le concurrent se trouve à gauche de la layline, les valeurs positives indiquent qu'il se trouve à droite de la layline. -enterMaster=Nom d'hôte de l'instance maître -errorStartingReplication=Erreur lors du lancement de la réplication à partir de l'hôte {0}/échange {1} : {2} -helpLines=Lignes d'aide +raceAverageAbsoluteCrossTrackErrorInMetersTooltip=Écart de route moyen absolu par rapport aux arcs de cercle reliant le début d''une portion de parcours à la fin d''une portion de parcours pour toutes les portions de parcours dans le lit du vent de cette course, en ignorant de quel côté de la layline de la course le concurrent se trouve. +raceAverageSignedCrossTrackErrorInMetersTooltip=Écart de route moyen enregistré par rapport aux arcs de cercle reliant le début d''une portion de parcours à la fin d''une portion de parcours pour toutes les portions de parcours dans le lit du vent de cette course. Les valeurs négatives indiquent que le concurrent se trouve à gauche de la layline, les valeurs positives indiquent qu''il se trouve à droite de la layline. +enterMaster=Nom d''hôte de l''instance maître +errorStartingReplication=Erreur lors du lancement de la réplication à partir de l''hôte {0}/échange {1} : {2} +helpLines=Lignes d''aide startLine=Ligne de départ -finishLine=Ligne d'arrivée -advantageLine=Ligne d'avantage +finishLine=Ligne d''arrivée +advantageLine=Ligne d''avantage courseMiddleLine=Ligne médiane de course -messagingPortNumber=Numéro de port d'échange de messages +messagingPortNumber=Numéro de port d''échange de messages servletPortNumber=Numéro de port Servlet registeredAt=Enregistré à {0} replicatingFromMaster=Réplication du serveur maître {0}:{2}, port de messagerie {3}:{1}, échange {4}, réplication {5} @@ -373,14 +373,14 @@ doYouReallyWantToRemoveRegatta=Voulez-vous vraiment supprimer la régate "{0}"  errorLoadingScoreCorrectionProviders=Erreur lors du chargement des fournisseurs de corrections de scores : {0} selectResultListToImportFrom=Sélectionner la liste des résultats depuis laquelle importer of=de -errorObtainingScoreCorrections=Erreur lors de l'accès aux corrections de scores du fournisseur {0} et manifestation {1} pour la catégorie de bateau {2} publié le {3}: {4} +errorObtainingScoreCorrections=Erreur lors de l''accès aux corrections de scores du fournisseur {0} et manifestation {1} pour la catégorie de bateau {2} publié le {3}: {4} assignRaceNumbersToRaceColumns=Affecter numéros de courses des résultats officiels aux colonnes de courses de palmarès importOfficialResults=Importer résultats officiels... selectAll=Sélectionner tout apply=Appliquer successfullyUpdatedScores=Mise à jour des scores réussie errorUpdatingScoresForLeaderboard=Erreur lors de la mise à jour des scores pour le palmarès {0} : {1} -maneuverTypesToShowWhenCompetitorIsClicked=Types de manœuvre à afficher lorsque l'on clique sur le concurrent +maneuverTypesToShowWhenCompetitorIsClicked=Types de manœuvre à afficher lorsque l''on clique sur le concurrent simulateAsLiveRace=Simulation de course en direct simulateWithOffset=Décalage avant le départ (en minutes) : boatClassDoesNotMatchSelectedRegatta=Les courses sélectionnées contiennent des catégories de bateaux qui ne sont pas identiques à la catégorie de bateau "{0}" de la régate sélectionnée. Aucune course ne sera chargée. @@ -388,7 +388,7 @@ regattaExistForSelectedBoatClass=Il existe au moins une régate pour les catégo reload=Recharger addRegatta=Ajouter régate... importRegattas=Importer régates... -exchangeName=Nom d'échange +exchangeName=Nom d''échange course=Parcours courseLayout=Configuration du parcours buoy=Bouée @@ -397,31 +397,31 @@ buoys=Bouées waypoint=Point de cheminement showAllCompetitors=Afficher tous les concurrents boatTails=Parcours effectué par chaque bateau -startFirstMarkTriangle=Triangle ligne de départ jusqu'à la première marque -resultImportUrls=URL d'importation des résultats -errorRefreshingResultImportUrlList=Erreur lors de l'actualisation de la liste des URL d'importation des résultats : {0} -successfullyUpdatedResultImportUrls=Mise à jour de la liste des URL d'importation des résultats réussie -errorRemovingResultImportUrls=Erreur lors de la suppression des URL d'importation des résultats : {0} +startFirstMarkTriangle=Triangle ligne de départ jusqu''à la première marque +resultImportUrls=URL d''importation des résultats +errorRefreshingResultImportUrlList=Erreur lors de l''actualisation de la liste des URL d''importation des résultats : {0} +successfullyUpdatedResultImportUrls=Mise à jour de la liste des URL d''importation des résultats réussie +errorRemovingResultImportUrls=Erreur lors de la suppression des URL d''importation des résultats : {0} pleaseEnterNonEmptyUrl=Saisissez une URL. -addResultImportUrl=Ajouter URL d'importation des résultats -errorAddingResultImportUrl=Erreur lors de l'ajout de l'URL d'importation des résultats : {0} +addResultImportUrl=Ajouter URL d''importation des résultats +errorAddingResultImportUrl=Erreur lors de l''ajout de l''URL d''importation des résultats : {0} remoteServerInstances=Instances de serveur distant localServer=Serveur local errorRefreshingSailingServers=Erreur lors de la mise à jour des instances SailingServer : {0} successfullyUpdatedSailingServers=Instances SailingServer correctement mises à jour errorRemovingSailingServers=Erreur lors de la suppression des instances SailingServer : {0} addSailingServer=Ajouter instance SailingServer -errorAddingSailingServer=Erreur lors de l'ajout de l'instance SailingServer : {0} -errorTryingToObtainLeaderboardContents=Erreur lors de la tentative d'obtention du contenu du palmarès : {0} +errorAddingSailingServer=Erreur lors de l''ajout de l''instance SailingServer : {0} +errorTryingToObtainLeaderboardContents=Erreur lors de la tentative d''obtention du contenu du palmarès : {0} lastScoreUpdate=Dernière mise à jour des scores -warningBrowserUnsupported=Ce site Web n'est pas optimisé pour votre navigateur. Utilisez un navigateur plus récent, tel que Firefox ou Chrome. +warningBrowserUnsupported=Ce site Web n''est pas optimisé pour votre navigateur. Utilisez un navigateur plus récent, tel que Firefox ou Chrome. newMark=Nouvelle marque controlPoint=Nom de la porte/marque errorUpdatingRaceCourse=Erreur lors de la mise à jour du parcours : {0} successfullyUpdatedCourse=Mise à jour du parcours réussie selectTwoMarksForGate=Sélectionnez deux marques pour créer une porte. -errorTryingToObtainTheMarksOfTheRace=Erreur lors de la tentative d'obtention des marques pour le parcours : {0} -errorTryingToObtainRaceCourse=Erreur lors de la tentative d'obtention du parcours : {0} +errorTryingToObtainTheMarksOfTheRace=Erreur lors de la tentative d''obtention des marques pour le parcours : {0} +errorTryingToObtainRaceCourse=Erreur lors de la tentative d''obtention du parcours : {0} insertWaypointBeforeSelected=Insérer point de cheminement avant la sélection insertWaypointAfterSelected=Insérer point de cheminement après la sélection addGate=Ajouter porte @@ -429,28 +429,28 @@ scoringSchemeLowPointSystem=Système de points a minima scoringSchemeHighPointSystem=Système de points avec bonus scoringSchemeHighPointEssOverall=Système de points avec bonus - ESS général (10) scoringSchemeHighPointEssOverall12=Système de points avec bonus - ESS général (12) -scoringSchemeHighPointEssOverall12Description=Score en points. Le vainqueur d'un Act totalise 12 points, le 2e - 11 points, etc. En cas d'égalité au classement général des Extreme Sailing Series, la victoire est accordée au concurrent ayant remporté le plus d'Act. Si l'égalité persiste, le résultat obtenu au dernier Act sera utilisé. +scoringSchemeHighPointEssOverall12Description=Score en points. Le vainqueur d''un Act totalise 12 points, le 2e - 11 points, etc. En cas d''égalité au classement général des Extreme Sailing Series, la victoire est accordée au concurrent ayant remporté le plus d''Act. Si l''égalité persiste, le résultat obtenu au dernier Act sera utilisé. scoringSchemeHighPointLastBreaksTie=Système de points avec bonus, dernière course à égalité scoringSchemeLowPointWinnerGetsZero=Système de points a minima, le vainqueur obtient zéro scoringSchemeWinnerGetsFive=Système de points avec bonus, le vainqueur obtient 5 points scoringSchemeWinnerGetsSix=Système de points avec bonus, le vainqueur obtient 6 points scoringSchemeWinnerGetsEight=Système de points avec bonus, le vainqueur obtient 8 points scoringSchemeHighPointMatchRacing=Système de points avec bonus, Match racing -scoringSchemeHighPointMatchRacingDescription=Le vainqueur d'un duel obtient 1 point, le perdant 0 points +scoringSchemeHighPointMatchRacingDescription=Le vainqueur d''un duel obtient 1 point, le perdant 0 points scoringSchemeWinnerGetsEightAndInterpolation=Système de points avec bonus, vainqueur 8 points, interpolé scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=Système de points à minima, avec éliminations et tours, le vainqueur obtient 0.7 points -scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=Une variante du schéma de scores a minima qui utilise des éliminations sous forme de tours. \nChaque tour est organisé comme série dans la régate, et l'ordre de départ de la flotte est inversé, \ncommençant par le numéro le plus élevé pour le premier tour. \nSi une finale et une finale des perdants ont lieu, utilisez 1 et 2 comme ordre. Commencez à trois pour le tour des demi-finales. -scoringSchemeLowPointForLeagueOverallLeaderboard=Système de points à minima, en cas d'égalité, le total des points de l'Act est utilisé, puis celui du dernier Act -scoringSchemeLowPointForLeagueOverallLeaderboardDescription=À la place du système habituel de comptage pour schémas à minima en cas d'égalité, les concurrents dont le total des points est égal sont départagés en comparant le total des points qu'ils ont obtenus dans tous les Act. Si l'égalité persiste, la victoire est accordée en fonction du classement dans le dernier Act. -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Système de points a minima, en cas d'égalité, seule la dernière série compte -scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=À la place du système habituel de comptage pour schémas à minima en cas d'égalité, le score de la dernière série sans exclusion de course est pris en compte si deux concurrents sont à égalité. +scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=Une variante du schéma de scores a minima qui utilise des éliminations sous forme de tours. \nChaque tour est organisé comme série dans la régate, et l''ordre de départ de la flotte est inversé, \ncommençant par le numéro le plus élevé pour le premier tour. \nSi une finale et une finale des perdants ont lieu, utilisez 1 et 2 comme ordre. Commencez à trois pour le tour des demi-finales. +scoringSchemeLowPointForLeagueOverallLeaderboard=Système de points à minima, en cas d''égalité, le total des points de l''Act est utilisé, puis celui du dernier Act +scoringSchemeLowPointForLeagueOverallLeaderboardDescription=À la place du système habituel de comptage pour schémas à minima en cas d''égalité, les concurrents dont le total des points est égal sont départagés en comparant le total des points qu''ils ont obtenus dans tous les Act. Si l''égalité persiste, la victoire est accordée en fonction du classement dans le dernier Act. +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnly=Système de points a minima, en cas d''égalité, seule la dernière série compte +scoringSchemeLowPointTieBreakBasedOnLastSeriesOnlyDescription=À la place du système habituel de comptage pour schémas à minima en cas d''égalité, le score de la dernière série sans exclusion de course est pris en compte si deux concurrents sont à égalité. scoringSchemeHighPointFirstGetsOne=Système de points avec bonus, le vainqueur obtient 1 point scoringSchemeHighPointFirstGetsTen=Système de points avec bonus, le vainqueur obtient 10 points scoringSchemeHighPointFirstGetsTenOrEight=Système de points avec bonus, le vainqueur obtient 10 points (ou 8) -scoringSchemeHighPointFirstGetsTenOrEightDescription=Score en points. Le vainqueur totalise 10 points, le deuxième 9, etc. En cas d'égalité, la victoire est accordée au concurrent qui a gagné le plus de courses. Si l'égalité persiste, la victoire est accordée en fonction du classement dans la dernière course. +scoringSchemeHighPointFirstGetsTenOrEightDescription=Score en points. Le vainqueur totalise 10 points, le deuxième 9, etc. En cas d''égalité, la victoire est accordée au concurrent qui a gagné le plus de courses. Si l''égalité persiste, la victoire est accordée en fonction du classement dans la dernière course. scoringSchemeHighPointFirstGetsTwelveOrEight=Système de points avec bonus, le vainqueur obtient 12 points (ou 8) -scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Score en points. Le vainqueur totalise 12 points, le deuxième 11, etc. En cas d'égalité, la victoire est accordée au concurrent qui a totalisé le plus de points. Si l'égalité persiste, la victoire est accordée en fonction du classement dans la dernière course. -scoringSystem=Système d'attribution des points +scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Score en points. Le vainqueur totalise 12 points, le deuxième 11, etc. En cas d''égalité, la victoire est accordée au concurrent qui a totalisé le plus de points. Si l''égalité persiste, la victoire est accordée en fonction du classement dans la dernière course. +scoringSystem=Système d''attribution des points createFlexibleLeaderboard=Créer palmarès flexible createRegattaLeaderboard=Créer palmarès régate createDefaultRegattaLeaderboard=Créer palmarès régate par défaut @@ -468,10 +468,10 @@ totalTimeSailedDownwindInSeconds=Durée totale avec vent arrière totalTimeSailedDownwindInSecondsTooltip=Durée totale pendant laquelle le concurrent a navigué avec un vent arrière au cours de la régate. totalTimeSailedUpwindInSeconds=Durée totale dans le lit du vent totalTimeSailedUpwindInSecondsTooltip=Durée totale pendant laquelle le concurrent a navigué dans le lit du vent au cours de la régate. -totalTimeSailedReachingInSeconds=Durée totale jusqu'à atteindre ce point +totalTimeSailedReachingInSeconds=Durée totale jusqu''à atteindre ce point totalTimeSailedReachingInSecondsTooltip=Durée totale que le concurrent a mis à atteindre des portions de parcours au cours de la régate. totalTimeSailedInSeconds=Durée totale -totalTimeSailedInSecondsTooltip=Durée totale de navigation du concurrent dans la régate, calculée à partir de l'heure du départ de la course. +totalTimeSailedInSecondsTooltip=Durée totale de navigation du concurrent dans la régate, calculée à partir de l''heure du départ de la course. totalDistanceTraveled=Distance totale totalDistanceTraveledTooltip=Distance totale naviguée dans la régate. totalAverageSpeedOverGround=∅ Vf @@ -509,9 +509,9 @@ pleaseSelectASeries=Sélectionnez une série. pleaseSelectARace=Sélectionnez une course. displayGroupsInReverseOrder=Afficher groupes en sens inverse actionConfigureUrl=Configurer URL -configureLeaderboardUrlDescription=Configurer le palmarès et obtenir l'URL correspondante à partir du lien +configureLeaderboardUrlDescription=Configurer le palmarès et obtenir l''URL correspondante à partir du lien embedded=Intégré -additionalUrlSettings=Options d'URL supplémentaires +additionalUrlSettings=Options d''URL supplémentaires restrictToSingleSelectedRace=Limiter à la seule course sélectionnée expandSelectedRace=Développer course sélectionnée showRaceDetails=Autoriser détails de la course @@ -526,17 +526,17 @@ factor=Facteur errorUpdatingIsMedalRace=Erreur lors la mise à jour des options de la course médaillée : {0} maneuverLoss=Perte suite à manœuvre averageManeuverLossInMeters=∅ perte suite à manœuvre -averageManeuverLossInMetersTooltip=Distance moyenne perdue au cours d'une manœuvre. +averageManeuverLossInMetersTooltip=Distance moyenne perdue au cours d''une manœuvre. averageTackLossInMeters=∅ perte suite à un virement averageTackLossInMetersTooltip=Distance moyenne perdue au cours des virements. -averageJibeLossInMeters=∅ perte suite à changement d'amure -averageJibeLossInMetersTooltip=Distance moyenne perdue au cours des changements d'amure. +averageJibeLossInMeters=∅ perte suite à changement d''amure +averageJibeLossInMetersTooltip=Distance moyenne perdue au cours des changements d''amure. shape=Forme pattern=Modèle legend=Légende live=en direct swissTimingArchiveConnector=Manifestations archivées SwissTiming -errorFetchingChartData=Erreur lors de l'accès aux données du graphique : {0} +errorFetchingChartData=Erreur lors de l''accès aux données du graphique : {0} loadingCompetitorData=Chargement des données du concurrent... competitorRegattaDataAfterRaceN={0} après la course {1} rankChart=Classement @@ -545,14 +545,14 @@ raceNetPointsTooltip=Points nets du concurrent dans la course regattaNetPointsTooltip=Points nets du concurrent dans la régate showRankChart=Afficher graphique du classement overallLeaderboardSelection=Palmarès général -errorTryingToObtainOverallLeaderboards=Erreur lors de la tentative d'obtention du palmarès général : {0} +errorTryingToObtainOverallLeaderboards=Erreur lors de la tentative d''obtention du palmarès général : {0} finished=terminé upcoming=à venir next=suivante inProgress=en cours passedTo=passé à {0} -gapChangeSinceLegStartInSeconds=Changement de l'écart -gapChangeSinceLegStartInSecondsTooltip=Changement de l'écart par rapport au concurrent en tête depuis le début de la dernière portion de parcours.\nUn chiffre négatif indique que l'écart a diminué ;\nun chiffre positif indique que l'écart a augmenté. +gapChangeSinceLegStartInSeconds=Changement de l''écart +gapChangeSinceLegStartInSecondsTooltip=Changement de l''écart par rapport au concurrent en tête depuis le début de la dernière portion de parcours.\nUn chiffre négatif indique que l''écart a diminué ;\nun chiffre positif indique que l''écart a augmenté. sideToWhichMarkAtLegStartWasRounded=Marque laissée à sideToWhichMarkAtLegStartWasRoundedTooltip=Côté duquel la marque a été contournée au début de la portion de parcours. raceIsLive=Course en direct : {0} @@ -566,29 +566,29 @@ generatePolarSheet=Générer fiche polaire polars=Diagrammes polaire polarSheetChart=Fiche polaire polarSheetMinimumDataSizePerGraph=Nombre minimum de points de données par diagramme. -polarSheetMinimumDataSizePerGraphTooltip=Les diagrammes comportant moins de points de données sous-jacents ne sont pas affichés visuellement.\nDe cette façon, aucun diagramme inutile n'est affiché pour \nla vitesse du vent s'il n'y a pas suffisamment de données. +polarSheetMinimumDataSizePerGraphTooltip=Les diagrammes comportant moins de points de données sous-jacents ne sont pas affichés visuellement.\nDe cette façon, aucun diagramme inutile n''est affiché pour \nla vitesse du vent s''il n''y a pas suffisamment de données. polarSheetMinimumDataSizePerAngle=Nombre minimum de points de données par angle. -polarSheetMinimumDataSizePerAngleTooltip=Dans chaque diagramme, seules les données relatives à des angles comportant au moins le nombre indiqué de\npoints de données sous-jacents seront affichées. Il est possible de masquer les sections\ninutiles du diagramme à l'aide de ce seuil. +polarSheetMinimumDataSizePerAngleTooltip=Dans chaque diagramme, seules les données relatives à des angles comportant au moins le nombre indiqué de\npoints de données sous-jacents seront affichées. Il est possible de masquer les sections\ninutiles du diagramme à l''aide de ce seuil. polarSheetMinimumWindConfidence=Valeur fiable minimale du vent polarSheetMinimumWindConfidenceTooltip=Seuls les points vent dont la valeur de fiabilité dépasse le seuil indiqué \nsont utilisés. Cette valeur de fiabilité se situe entre 0 et 1. polarSheetMinimumConfidenceMeasure=Indicateur de fiabilité minimale -polarSheetMinimumConfidenceMeasureTooltip=Indicateur de fiabilité minimale pour un point affiché dans le diagramme.\nSi celui-ci se situe en-dessous d'un seuil donné, le point ne sera pas affiché.\nL'indicateur se situe entre 0 et 1, il est déterminé\nà l'aide de mesures statistiques. +polarSheetMinimumConfidenceMeasureTooltip=Indicateur de fiabilité minimale pour un point affiché dans le diagramme.\nSi celui-ci se situe en-dessous d''un seuil donné, le point ne sera pas affiché.\nL''indicateur se situe entre 0 et 1, il est déterminé\nà l''aide de mesures statistiques. polarSheetUseOnlyWindGaugeData=Utiliser uniquement des données de vent de jauges pour la vitesse du vent -polarSheetUseOnlyWindGaugeDataTooltip=Si vous considérez uniquement les données de vitesse provenant de jauges de vent, \nvous vous assurez d'exclure des vitesses de vent estimées et saisies manuellement, susceptibles de fausser le diagramme polaire. -polarSheetUseOnlyEstimationData=Utiliser uniquement l'estimation pour la direction du vent -polarSheetUseOnlyEstimationDataTooltip=En utilisant l'estimation précise du vent pour la direction du vent,\nvous corrigez des diagrammes polaires qui ont pivoté suite à des données de vent \nde jauge non valides. +polarSheetUseOnlyWindGaugeDataTooltip=Si vous considérez uniquement les données de vitesse provenant de jauges de vent, \nvous vous assurez d''exclure des vitesses de vent estimées et saisies manuellement, susceptibles de fausser le diagramme polaire. +polarSheetUseOnlyEstimationData=Utiliser uniquement l''estimation pour la direction du vent +polarSheetUseOnlyEstimationDataTooltip=En utilisant l''estimation précise du vent pour la direction du vent,\nvous corrigez des diagrammes polaires qui ont pivoté suite à des données de vent \nde jauge non valides. polarSheetRemoveOutliers=Supprimer des valeurs aberrantes (approche basée sur la distance) polarSheetRemoveOutliersTooltip=Les valeurs aberrantes sont supprimées par une approche basée sur la distance.\nLes paramètres peuvent être ajustés ci-dessous. polarSheetOutlierDetectionRadius=Rayon de voisinage de détection des valeurs aberrantes -polarSheetOutlierDetectionRadiusTooltip=Le rayon utilisé dans l'algorithme de \ndétection de valeurs aberrantes basé sur la distance. +polarSheetOutlierDetectionRadiusTooltip=Le rayon utilisé dans l''algorithme de \ndétection de valeurs aberrantes basé sur la distance. polarSheetOutlierDetectionMinimumPerc=Pourcentage de voisinage minimal de détection de valeurs aberrantes polarSheetOutlierDetectionMinimumPercTooltip=Le pourcentage de points de données de voisinage/points de données globaux \ndoit être inférieur à la valeur donnée pour que le point soit considéré comme une valeur aberrante. -polarSheetNumberOfHistogramColumns=Nombre de colonnes d'histogramme par plage de vent +polarSheetNumberOfHistogramColumns=Nombre de colonnes d''histogramme par plage de vent polarSheetWindSteppingInKnots=Évolution du vent en nœuds polarSheetWindSteppingMaxDistance=Distance max. au niveau du vent polarSheetWindSteppingMaxDistanceTooltip=Définit un rayon maximal pour lequel des points seront affectés aux niveaux du vent. polarSheetSplitByWindGauges=Fractionner des sources de vent -polarSheetSplitByWindGaugesTooltip=Le fractionnement des sources de vent permet d'améliorer la recherche pour des jauges de vents défavorables. \nLa précision statistique ne peut pas être garantie. Un même point peut être \npris en compte de multiples fois dans les fiches polaires en résultant (pour des jauges de vent différentes). +polarSheetSplitByWindGaugesTooltip=Le fractionnement des sources de vent permet d''améliorer la recherche pour des jauges de vents défavorables. \nLa précision statistique ne peut pas être garantie. Un même point peut être \npris en compte de multiples fois dans les fiches polaires en résultant (pour des jauges de vent différentes). applyMinimumWindConfidence=Appliquer fiabilité minimale du vent applyMinimumWindConfidenceTooltip=Si cette case est cochée, la valeur de la case ci-dessus sera utilisée comme valeur de fiabilité valide minimale du vent au cours de la génération. windRangeDistribution=Distribution dans la plage du vent @@ -597,7 +597,7 @@ competitorColumnTooltip=Noms des membres de ce concurrent sailIdColumnTooltip=Indique le pavillon du pays et le numéro de voile du concurrent. rankColumnTooltip=La place au classement général de ce concurrent dans la régate. carryColumnTooltip=Points accumulés lors des autres courses -totalNetPointsColumnTooltip=Total net des points d'un concurrent dans la régate.\nLe tri est effectué en fonction du classement, et non des points. +totalNetPointsColumnTooltip=Total net des points d''un concurrent dans la régate.\nLe tri est effectué en fonction du classement, et non des points. windData=Données de vent gpsData=Données GPS status=Statut @@ -609,7 +609,7 @@ angleAndTotalNumberOfDataPointsAndCovAndCm=Angle : {0} ; Nombre total de point buoyZone=Zone de bouée radiusInMeters=Rayon (m) filterRegattasByName=Filtrer régates par nom -noRegattasYet=Il n'y a pas encore de régate. +noRegattasYet=Il n''y a pas encore de régate. addCourseArea=Ajouter zone de course courseAreas=Zones de course courseArea=Zone de course @@ -617,13 +617,13 @@ pleaseEnterNonEmptyCourseArea=Saisissez une zone de course. pleaseSelectACourseArea=Sélectionnez une zone de course. lastUpperFlag=Pavillon supérieur lastLowerFlag=Pavillon inférieur -cannotAddRacesToRegattaLeaderboardButOnlyToRegatta=Il s'agit d'un palmarès de régate. Vous pouvez uniquement ajouter des courses à ce palmarès dans la définition de la régate. +cannotAddRacesToRegattaLeaderboardButOnlyToRegatta=Il s''agit d''un palmarès de régate. Vous pouvez uniquement ajouter des courses à ce palmarès dans la définition de la régate. correctScore=Corriger score correctScoreFor=Corriger score pour le concurrent {0} dans la course {1} penaltyOrRedress=Pénalité/Réparation totalScore=Total des points -timePointMustBeAfterStartOfTracking=L'heure doit être postérieure au début du suivi. -timePointMustBeBeforeEndOfTracking=L'heure doit être antérieure au début du suivi. +timePointMustBeAfterStartOfTracking=L''heure doit être postérieure au début du suivi. +timePointMustBeBeforeEndOfTracking=L''heure doit être antérieure au début du suivi. regattaUsedForTheTrackedRace=Régate utilisée pour la course suivie tracTracUpdateUrl=URL de mise à jour du serveur TracTrac passingInstructions=Instructions de passage @@ -631,7 +631,7 @@ refreshNow=Actualiser maintenant stopUpdating=Arrêter mise à jour startUpdating=Lancer mise à jour currentTime=Heure actuelle : -tractracUsername=Nom d'utilisateur TracTrac +tractracUsername=Nom d''utilisateur TracTrac tractracPassword=Mot de passe TracTrac operatorEquals=Égal à operatorNotEqualTo=Non égal à @@ -650,7 +650,7 @@ distanceToLineFiveSecondsBeforeStart=Distance par rapport à la ligne 5 sec. av speedOverGroundAtRaceStart=Vf au départ speedOverGroundFiveSecondsBeforeStart=Vf 5 sec. avant le départ speedOverGroundWhenPassingStart=Vf au moment du départ -distanceToLineAtRaceStartTooltip=Distance par rapport à la ligne de départ à l'heure du départ de la course ; distance par rapport au côté le plus proche de la ligne si le concurrent se trouve au-delà des extrémités de la ligne. +distanceToLineAtRaceStartTooltip=Distance par rapport à la ligne de départ à l''heure du départ de la course ; distance par rapport au côté le plus proche de la ligne si le concurrent se trouve au-delà des extrémités de la ligne. distanceToLineFiveSecondsBeforeStartTooltip=Distance par rapport à la ligne de départ cinq secondes avant le départ ; distance par rapport au côté le plus proche de la ligne si le concurrent se trouve au-delà des extrémités de la ligne. speedOverGroundAtRaceStartTooltip=Vitesse fond au moment du départ de la course speedOverGroundFiveSecondsBeforeStartTooltip=Vitesse fond cinq secondes avant le départ @@ -694,7 +694,7 @@ filterNothing=Ne pas filtrer topNCompetitorsByRaceRank=Tête du classement de la course {0} topNCompetitorsByTotalRank=Tête du classement général {0} simulator=Simulateur -optionsBar=Barre d'options +optionsBar=Barre d''options simulateButton=Prédire setup=Configurer strength=Force (en nd) @@ -743,33 +743,33 @@ showFollowingCourseAreas=Afficher les zones de course suivantes showFollowingRegattas=Afficher les régates suivantes showOnlyRacesOfSameDay=Afficher uniquement les courses du même jour showOnlyCurrentlyRunningRaces=Afficher les courses en cours -seriesDefinesResultDiscardingRule=La série définit les règles d'élimination du résultat. +seriesDefinesResultDiscardingRule=La série définit les règles d''élimination du résultat. addSeries=Ajouter série -regattaDefinesResultDiscardingRules=La régate définit les règles d'élimination du résultat. +regattaDefinesResultDiscardingRules=La régate définit les règles d''élimination du résultat. startsWithZeroScore=La série commence avec un score à zéro. masterDataImportPanel=Importation des données de base -importSuccess=Réussite\n{0} groupe(s) de palmarès, {1} palmarès, {2} manifestation(s) et {3} régate(s) créés +importSuccess=Réussite\n{0} groupe(s) de palmarès, {1} palmarès, {2} manifestation(s) et {3} régate(s) créés. TODO {4} importSuccessOverwriteInfo=Les régates suivantes ont été écrasées, vous devez suivre à nouveau les courses : regattaOverviewConfiguration=Configuration de la synthèse des régates firstRaceIsNonDiscardableCarryForward=Départs avec report sans élimination addReplicationMaster=Connexion au serveur maître de réplication connect=Connexion connectToMaster=Connexion à un serveur maître -exchangeHost=Nom d'hôte d'échange de messages -explainExchangeHostName=Nom de l'hôte sur lequel la file d'attente des messages s'exécute. -explainReplicationHostname=Nom de l'hôte sur lequel le serveur maître de réplication s'exécute. -explainReplicationExchangeName=Nom de la file d'attente d'échange. Le nom doit être identique à celui qui est configuré dans le serveur maître. -explainReplicationExchangePort=Port de la file d'attente d'échange de messages. Utilisé pour toutes les données après le chargement initial. -explainReplicationServletPort=Numéro de port Servlet utilisé pour la connexion afin d'enregistrer le réplica et recevoir le chargement initial. +exchangeHost=Nom d''hôte d''échange de messages +explainExchangeHostName=Nom de l''hôte sur lequel la file d''attente des messages s''exécute. +explainReplicationHostname=Nom de l''hôte sur lequel le serveur maître de réplication s''exécute. +explainReplicationExchangeName=Nom de la file d''attente d''échange. Le nom doit être identique à celui qui est configuré dans le serveur maître. +explainReplicationExchangePort=Port de la file d''attente d''échange de messages. Utilisé pour toutes les données après le chargement initial. +explainReplicationServletPort=Numéro de port Servlet utilisé pour la connexion afin d''enregistrer le réplica et recevoir le chargement initial. explainReplicasRegistered=Copie enregistrée (ce serveur est un serveur maître) : explainConnectionsToMaster=Connexions à un serveur maître (ce serveur est un réplica) : explainNoConnectionsToMaster=Aucune connexion à un serveur maître configurée. Cliquez sur le bouton Connexion à un serveur maître pour en configurer une. -explainNoConnectionsFromReplicas=Aucune connexion à partir d'un réplica trouvée. Vous pouvez connecter des réplicas en utilisant leur console d'administration. +explainNoConnectionsFromReplicas=Aucune connexion à partir d''un réplica trouvée. Vous pouvez connecter des réplicas en utilisant leur console d''administration. stopConnectionToMaster=Arrêter réplication asLink=En tant que lien noStarttimeAnnouncedYet=En attente -raceIsRunning=En cours d'exécution -raceIsFinishing=En cours d'achèvement +raceIsRunning=En cours d''exécution +raceIsFinishing=En cours d''achèvement raceIsFinished=Terminé raceIsScheduled=Planifié raceIsInStartphase=Lancer phase @@ -786,7 +786,7 @@ protestTimeFinishesAt=se termine protestTimeFinishedAt=terminé flags=Pavillons lastUpdate=Dernière mise à jour -noMoreRacingToday=Plus aucune course aujourd'hui +noMoreRacingToday=Plus aucune course aujourd''hui furtherSignalsAshore=Signaux ultérieurs à terre earlyStarters=Faux départs showingDetailsOfRace=Affichage des détails de la course {0} @@ -813,14 +813,14 @@ zuluIndiaRemoved=Pavillon de départ - départ avec pénalités pour les faux d classFlagRemoved=Pavillon affalé - signal de départ de la course xray=Rappel individuel - faux départs signalés firstSubstitute=Rappel général - trop de faux départs signalés - répétition de la procédure de départ -blueFlagDisplayed=Pavillon envoyé - le premier concurrent a franchi la ligne d'arrivée -blueFlagRemoved=Pavillon affalé - le dernier concurrent a franchi la ligne d'arrivée ou le temps limite d'arrivée est dépassé +blueFlagDisplayed=Pavillon envoyé - le premier concurrent a franchi la ligne d''arrivée +blueFlagRemoved=Pavillon affalé - le dernier concurrent a franchi la ligne d''arrivée ou le temps limite d''arrivée est dépassé golfRemoved=Pavillon supprimé - porte fermée -answeringPennantOverAlphaDisplayed=Pavillon envoyé - départ retardé - plus de courses aujourd'hui +answeringPennantOverAlphaDisplayed=Pavillon envoyé - départ retardé - plus de courses aujourd''hui answeringPennantOverHotelDisplayed=Pavillon envoyé - départ retardé - signaux ultérieurs à terre answeringPennantDisplayed=Pavillon envoyé - départ retardé answeringPennantRemoved=Pavillon affalé - la procédure de départ sera lancée dans une minute -novemberOverAlphaDisplayed=Pavillon envoyé - course annulée - plus de courses aujourd'hui +novemberOverAlphaDisplayed=Pavillon envoyé - course annulée - plus de courses aujourd''hui novemberOverHotelDisplayed=Pavillon envoyé - course annulée - signaux ultérieurs à terre novemberDisplayed=Pavillon envoyé - course annulée bravoDisplayed=Début du temps de réclamation @@ -833,24 +833,24 @@ dataBeforeAfter=Données obtenues avant/après la course rawFixes=Toutes les positions (y compris les valeurs aberrantes) importRemoteHost=Hôte distant : importFetchRemoteLgs=Accéder à la liste des groupes de palmarès -importUrlInvalid=URL non valide pour l'accès aux groupes de palmarès : {0} -importGetLeaderboardsFailed=Échec de la requête GET pour l'obtention des groupes de palmarès pour l'hôte {0}, erreur {1} +importUrlInvalid=URL non valide pour l''accès aux groupes de palmarès : {0} +importGetLeaderboardsFailed=Échec de la requête GET pour l''obtention des groupes de palmarès pour l''hôte {0}, erreur {1} importNoDataReturned=Aucune donnée retournée par le serveur -importServerError=Échec de la requête GET pour l'obtention des groupes de palmarès avec erreur de serveur. Pour plus d'informations, consultez les journaux du serveur. +importServerError=Échec de la requête GET pour l''obtention des groupes de palmarès avec erreur de serveur. Pour plus d''informations, consultez les journaux du serveur. importOverrideSwitchLabel=Remplacer données existantes si les noms et ID correspondent importSelectedLeaderboardGroups=Importer groupes de palmarès sélectionnés importSelectAtLeastOne=Vous devez sélectionner au moins un groupe de palmarès à importer. deselectAll=Désélectionner tout polarDiagramButton=Diagramme polaire ratioBetweenTimeSinceLastPositionFixAndAverageSamplingInterval=Écart GPS -ratioBetweenTimeSinceLastPositionFixAndAverageSamplingIntervalTooltip=Ratio entre l'heure de réception de la dernière position GPS position et l'intervalle d'échantillonnage moyen +ratioBetweenTimeSinceLastPositionFixAndAverageSamplingIntervalTooltip=Ratio entre l''heure de réception de la dernière position GPS position et l''intervalle d''échantillonnage moyen trackingQuality=Qualité du suivi legType=Type de portion de parcours sailID=Numéro de voile seriesLeaderboard=Palmarès de la série regattaLeaderboards=Palmarès de la régate clearSelection=Effacer la sélection -running=En cours d'exécution +running=En cours d''exécution runAsSubstantive=Exécuter done=Terminé lastFinished=Fin de dernière exécution @@ -859,15 +859,15 @@ times=durées dataAmount=Volume de données averageCleanedServerTime=∅ Durée de nettoyage du serveur averageCleanedOverallTime=∅ Durée globale de nettoyage -dataMiningBenchmarkResults=Résultats benchmark d'exploration de données +dataMiningBenchmarkResults=Résultats benchmark d''exploration de données serverTime=Heure du serveur confidenceShouldBeBetween=Les valeurs de fiabilité doivent se situer entre 0 et 1. minDataValuesNeedToBeAtLeastZero=Les valeurs de tailles de données minimales ne peuvent pas être négatives. -numberOfColumnsAtLeast2=Le nombre de colonnes d'histogrammes doit être supérieur à un. +numberOfColumnsAtLeast2=Le nombre de colonnes d''histogrammes doit être supérieur à un. outlierRadiusNeedsToBePositiveString=Le rayon des valeurs aberrantes doit être un nombre positif. outlierMinimumNeighborhoodPctString=Le pourcentage de voisinage des valeurs aberrantes doit être un nombre positif, max. 1. oneOrMoreParametersAreEmpty=Les zones de paramètres ne peuvent pas être vides. -errorWhileAddingSeriesToChart=Une erreur s'est produite lors de la tentative d'ajout\nd'une nouvelle série au graphique. +errorWhileAddingSeriesToChart=Une erreur s''est produite lors de la tentative d''ajout\nd''une nouvelle série au graphique. generatingPolarSheet=Génération de la fiche polaire... dataCount=Volume des données generationFinished=Génération terminée @@ -878,17 +878,17 @@ selectSheet=Sélectionner fiche cleanedServerTime=Durée de nettoyage du serveur overallTime=Durée globale cleanedOverallTime=Durée globale de nettoyage -dataMiningResult=Résultat d'exploration de données +dataMiningResult=Résultat d''exploration de données groupBy=Regrouper par statisticToCalculate=Calculer statistiques queryResultsChartSubtitle={0} entrées de données analysées en {1} secondes noQuerySelected=Aucune requête sélectionnée runAutomatically=Exécuter automatiquement windImport_Upload=Charger -windImport_Title=Importer vent de l'expédition +windImport_Title=Importer vent de l''expédition windImport_BoatId=N° du bateau : -windImport_SelectedRacesWarning=Voulez-vous réellement importer les données de vent dans les {0} courses ?\nNotez que seules les courses dont l'intervalle est pertinent seront prises en compte. -windImport_AllRacesWarning=Voulez-vous réellement importer les données de vent dans toutes les courses ?\nNotez que seules les courses dont l'intervalle est pertinent seront prises en compte. +windImport_SelectedRacesWarning=Voulez-vous réellement importer les données de vent dans les {0} courses ?\nNotez que seules les courses dont l''intervalle est pertinent seront prises en compte. +windImport_AllRacesWarning=Voulez-vous réellement importer les données de vent dans toutes les courses ?\nNotez que seules les courses dont l''intervalle est pertinent seront prises en compte. windImport_ResultHeader=Données de vent importées de : {0} à : {1}. Appliqué à {2} course(s). windImport_ResultEntry=Course : {0} ({1}) - {2} points de : {3} à : {4} windImport_ResultError=Erreur : {0} @@ -896,20 +896,20 @@ gribWindImport_Title=Importer données de vent à partir de fichiers GRIB showWindSpeedSeriesTooltip=Bascule la visibilité de la vitesse du vent pour toutes les sources de données showWindDirectionSeriesTooltip=Bascule la visibilité de la direction du vent pour toutes les sources de données combinedWindSourceTypeTooltip=Combine toutes les autres sources de vent en un ensemble de données -legMiddleWindSourceTypeTooltip=Données de vent combinées au point du milieu de la route loxodromique d'une portion de parcours +legMiddleWindSourceTypeTooltip=Données de vent combinées au point du milieu de la route loxodromique d''une portion de parcours courseBasedWindSourceTypeTooltip=Valeur basée sur la configuration du parcours (supposant que le départ de la course se fait avec une portion de parcours dans le lit du vent) trackBasedEstimationWindSourceTypeTooltip=Données calculées à partir du suivi du concurrent windSensorWindSourceTypeTooltip=Données captées à partir de systèmes de mesure mobiles webWindSourceTypeTooltip=Valeurs de données définies manuellement raceCommitteeWindSourceTypeTooltip=Valeurs de données définies manuellement par les membres du comité de course sheetName=Nom de la fiche -sheetNameTooltip=Vous pouvez nommer votre fiche polaire à l'aide de la zone de texte.\nLe système génère un nom basé sur la catégorie du bateau \nsi aucun nom n'est indiqué. +sheetNameTooltip=Vous pouvez nommer votre fiche polaire à l''aide de la zone de texte.\nLe système génère un nom basé sur la catégorie du bateau \nsi aucun nom n''est indiqué. timeDownwind=Vent arrière (durée) -timeReaching=Durée jusqu'à l'arrivée +timeReaching=Durée jusqu''à l''arrivée timeUpwind=Dans le lit du vent (durée) raceTimeTooltip=Durée de navigation totale dans cette course, chronométrée à partir du moment où le concurrent passe le point de cheminement du départ \n(et non pas lors du départ de la course) raceTimeDownwindTooltip=Durée totale de navigation vent arrière dans cette course -raceTimeReachingTooltip=Durée totale de navigation jusqu'à l'arrivée dans cette course +raceTimeReachingTooltip=Durée totale de navigation jusqu''à l''arrivée dans cette course raceTimeUpwindTooltip=Durée totale de navigation dans le lit du vent dans cette course noStatisticSelectedError=Aucune statistique à calculer sélectionnée noCustomGrouperScriptTextError=Script de regroupement vide @@ -918,11 +918,11 @@ noGrouperSelectedError=Aucun type de regroupement sélectionné noDataRetrieverChainDefinitonSelectedError=Aucun récupérateur de données sélectionné queryNotValidBecause=Aucune requête possible dû à dataMining=Exploration de données -errorRunningDataMiningQuery=Une erreur s'est produite lors de l'exécution de la requête. -hideToolbar=Masquer barre d'outils +errorRunningDataMiningQuery=Une erreur s''est produite lors de l''exécution de la requête. +hideToolbar=Masquer barre d''outils showSeriesLeaderboards=Afficher palmarès de la série showOverallLeaderboard=Afficher palmarès général -lineAngleToWindAndAdvantage=longueur : {0} m\nangle au vent : {1}°\ncôté {2} a {3} m d'avantage +lineAngleToWindAndAdvantage=longueur : {0} m\nangle au vent : {1}°\ncôté {2} a {3} m d''avantage doYouReallyWantToRemoveEvents=Voulez-vous vraiment supprimer les manifestations ? doYouReallyWantToRemoveEvent=Voulez-vous vraiment supprimer la manifestation {0} ? line=Ligne @@ -936,10 +936,10 @@ successfullyAllowedCompetitorReset=Autorisation de rechargement de concurrent(s) id=ID allowReload=Autoriser rechargement compress=Comprimer -compressTooltip=Utiliser seulement si l'instance de serveur d'exportation \ns'exécute au moins avec le commit 0fbf6071dea125bec4a56dee55d61c99def4a62e. -queryRunner=Outil d'exécution de requêtes -rerunQueryAfterRefresh=Exécuter la requête de nouveau après l'actualisation -refreshIntervalMustntBeEmpty=L'intervalle d'actualisation ne doit pas être vide. +compressTooltip=Utiliser seulement si l''instance de serveur d''exportation \ns''exécute au moins avec le commit 0fbf6071dea125bec4a56dee55d61c99def4a62e. +queryRunner=Outil d''exécution de requêtes +rerunQueryAfterRefresh=Exécuter la requête de nouveau après l''actualisation +refreshIntervalMustntBeEmpty=L''intervalle d''actualisation ne doit pas être vide. selectionTables=Tables de sélection addConfiguration=Ajouter configuration noConfigurations=Aucune configuration disponible @@ -948,7 +948,7 @@ allowedCourseAreas=Zones de course autorisées minimumRoundsForCourse=Nombre de tours min. pour la course maximumRoundsForCourse=Nombre de tours max. pour la course resultsMailRecipient=Résultats destinataire du mail -deviceConfiguration=Configuration de l'appareil +deviceConfiguration=Configuration de l''appareil none=Auc. courseDesignerMode=Concepteur de la course racingProcedure=Instructions de course @@ -964,59 +964,59 @@ sailingWorldCupStart=Départ coupe du monde de la voile setConfiguration=Activer configuration classFlag=Pavillon de classe classFlagHelpText=Active le pavillon de la classe utilisée pour {0}. Sélectionnez ''Ne pas écraser'' pour activer le pavillon par défaut pour ces instructions. -individualRecallHelpText=Si cette option est activée, l'officiel de course a la possibilité d'appeler pour un rappel individuel. -resultEntryHelpText=Si cette option est activée, l'officiel de course a la possibilité d'entrer des résultats pendant et après la phase d'arrivée. +individualRecallHelpText=Si cette option est activée, l''officiel de course a la possibilité d''appeler pour un rappel individuel. +resultEntryHelpText=Si cette option est activée, l''officiel de course a la possibilité d''entrer des résultats pendant et après la phase d''arrivée. startmodeFlags=Pavillons de types de départ startmodeFlagsHelpText=Définit les pavillons de types de départ disponibles. Sélectionnez "Auc." pour activer les pavillons par défaut des instructions. gateStart=Départ au lièvre activatePathfinder=Activer bateau ouvreur -pathfinderHelpText=Si cette option est activée, l'officiel de course peut définir le bateau ouvreur. +pathfinderHelpText=Si cette option est activée, l''officiel de course peut définir le bateau ouvreur. essStart=Départ ESS basicStart=Départ basique leagueStart=Départ de ligue configured=Configuré overwriteRacingProceduresConfiguration=Activer configuration de la régate -overwriteRacingProceduresConfigurationHelpText=L'activation de cette option fournira une configuration de base de la régate pour toutes les options non configurées dans la configuration spécifique de la régate. +overwriteRacingProceduresConfigurationHelpText=L''activation de cette option fournira une configuration de base de la régate pour toutes les options non configurées dans la configuration spécifique de la régate. setStartTime=Définir heure de départ currentPass=Passage actuel -setStartTimeDescription=Sélectionnez une nouvelle heure de départ pour la course. Si vous voulez définir une heure de départ qui corresponde à une heure du passé, vous devez cocher cette case pour mettre à jour le nombre de passages. Notez qu'en modifiant le nombre de passages, vous perdrez toutes les informations concernant le passage précédent (comme les pavillons et manifestations). +setStartTimeDescription=Sélectionnez une nouvelle heure de départ pour la course. Si vous voulez définir une heure de départ qui corresponde à une heure du passé, vous devez cocher cette case pour mettre à jour le nombre de passages. Notez qu''en modifiant le nombre de passages, vous perdrez toutes les informations concernant le passage précédent (comme les pavillons et manifestations). setTrackingTimesDescription=Définissez le début et la fin du suivi pour la course. -hasAdditionalGolfDownTime=Activer temps d'arrêt supplémentaire -additionalGolfDownTimeHelpText=Activer temps d'arrêt supplémentaire +hasAdditionalGolfDownTime=Activer temps d''arrêt supplémentaire +additionalGolfDownTimeHelpText=Activer temps d''arrêt supplémentaire invalidColor=Couleur non valide : {0} igtimiAccounts=Comptes Igtimi -errorFetchingIgtimiAccounts=Erreur lors de l'accès à tous les comptes Igtimi : {0} +errorFetchingIgtimiAccounts=Erreur lors de l''accès à tous les comptes Igtimi : {0} addIgtimiAccount=Ajouter compte Igtimi -errorAuthorizingAccessToIgtimiUser=Erreur lors de l'autorisation d'accès pour l'utilisateur {0} : {1} -successfullyAuthorizedAccessToIgtimiUser=Autorisation d'accès réussie pour l'utilisateur : {0} -couldNotAuthorizedAccessToIgtimiUser=Autorisation pour l'utilisateur {0} échouée : mot de passe ou nom d'utilisateur non valide. -errorGettingIgtimiAuthorizationUrl=Erreur lors de l'accès à l'URL d'autorisation Igtimi : {0} +errorAuthorizingAccessToIgtimiUser=Erreur lors de l''autorisation d''accès pour l''utilisateur {0} : {1} +successfullyAuthorizedAccessToIgtimiUser=Autorisation d''accès réussie pour l''utilisateur : {0} +couldNotAuthorizedAccessToIgtimiUser=Autorisation pour l''utilisateur {0} échouée : mot de passe ou nom d''utilisateur non valide. +errorGettingIgtimiAuthorizationUrl=Erreur lors de l''accès à l''URL d''autorisation Igtimi : {0} addIgtimiUser=Ajouter utilisateur Igtimi doYouReallyWantToRemoveLeaderboards=Voulez-vous vraiment supprimer les palmarès ? -errorTryingToRemoveIgtimiAccount=Erreur lors de la tentative de suppression du compte Igtimi pour l'utilisateur {0}. -successfullyRemoveIgtimiAccount=Suppression du compte Igtimi pour l'utilisateur {0} réussie. -eMailMustNotBeEmpty=L'adresse e-mail ne doit pas être vide. +errorTryingToRemoveIgtimiAccount=Erreur lors de la tentative de suppression du compte Igtimi pour l''utilisateur {0}. +successfullyRemoveIgtimiAccount=Suppression du compte Igtimi pour l''utilisateur {0} réussie. +eMailMustNotBeEmpty=L''adresse e-mail ne doit pas être vide. emailAddress=Adresse e-mail password=Mot de passe searchTag=Balise de recherche doYouReallyWantToRemoveLeaderboard=Voulez-vous vraiment supprimer le palmarès ''{0}'' ? metaLeaderboardCannotBeChanged=Ce palmarès est de type méta. Vous ne pouvez pas le modifier ici. -failedToSetNewStartTime=Définition de la nouvelle heure de départ échouée. Cela peut arriver lorsque la même heure de départ existe déjà dans le journal de course ou lorsque quelqu'un d'autre a ajouté une heure de départ plus récente (sous forme d'ID de passage et d'heure logique) que celle que vous venez d'ajouter. -doYouReallyWantToRemoveIgtimiAccount=Souhaitez-vous réellement supprimer le compte Igtimi qui permet à l'utilisateur {0} d'accéder aux données ? +failedToSetNewStartTime=Définition de la nouvelle heure de départ échouée. Cela peut arriver lorsque la même heure de départ existe déjà dans le journal de course ou lorsque quelqu''un d''autre a ajouté une heure de départ plus récente (sous forme d''ID de passage et d''heure logique) que celle que vous venez d''ajouter. +doYouReallyWantToRemoveIgtimiAccount=Souhaitez-vous réellement supprimer le compte Igtimi qui permet à l''utilisateur {0} d''accéder aux données ? igtimiWindImport=Importer le vent depuis Igtimi -seeIgtimiTabForAccountSettings=Afficher l'onglet ''Igtimi'' pour voir les options de compte qui déterminent quelles données Igtimi seront prises en compte. +seeIgtimiTabForAccountSettings=Afficher l''onglet ''Igtimi'' pour voir les options de compte qui déterminent quelles données Igtimi seront prises en compte. importWindFromIgtimi=Importer le vent depuis Igtimi -errorImportingIgtimiWind=Erreur lors de l'importation des données du vent depuis Igtimi : {0} +errorImportingIgtimiWind=Erreur lors de l''importation des données du vent depuis Igtimi : {0} resultFromIgtimiWindImport=Le nombre suivant de points vent ont été importés pour les courses référencées : {0} -timeToStart={0} jusqu'au départ +timeToStart={0} jusqu''au départ timeSinceStart={0} depuis le départ -distanceToLine=Distance jusqu'à la ligne de départ -beatAngleTooltip=L'angle entre la direction du concurrent et le vent. -beatAngle=Angle d'attaque +distanceToLine=Distance jusqu''à la ligne de départ +beatAngleTooltip=L''angle entre la direction du concurrent et le vent. +beatAngle=Angle d''attaque showBoatClassChartsLabel=Vous pouvez également afficher le diagramme global pour les catégories de bateau disponibles. showDiagram=Afficher diagramme runAutomaticallyTooltip=Exécutez la requête automatiquement, par exemple après avoir modifié les statistiques ou le regroupement. -rerunQueryAfterRefreshTooltip=Réexécute la requête après l'actualisation des tables. +rerunQueryAfterRefreshTooltip=Réexécute la requête après l''actualisation des tables. queryDefinitionProvider=Fournisseur de définitions de requêtes statisticProvider=Fournisseur de statistiques calculateThe=Calculer le/la @@ -1041,22 +1041,22 @@ remove_what=Supprimer {0} pleaseEnterA=Veuillez saisir un(e) {0} pingPosition=Effectuez un test ping pour la position {0}. pleaseEnterAValidValueFor=Saisissez une valeur valide pour {0} ({1}). -copyCourseAndCompetitors=Copier le parcours et les concurrents dans d'autres courses +copyCourseAndCompetitors=Copier le parcours et les concurrents dans d''autres courses setTrackingTimes=Définissez les durées de suivi. nowSelectRaceColumnAndFleetToCopyTo=Sélectionnez maintenant la colonne de la course et la flotte auxquelles le parcours doit être copié. selectRowInTableToCopyCourse=Sélectionnez une seule ligne dans la table vers laquelle le parcours doit être copié. -deviceId=ID de l'appareil -deviceType=Type d'appareil +deviceId=ID de l''appareil +deviceType=Type d''appareil mappedToType=Mappé au type mappedTo=Mappé à -deviceMappings=Mappages d'appareils -atMostOneEndOfTheTimeRangeMayBeOpen=Au moins une extrémité de l'intervalle de temps du mappage doit rester ouverte (ne pas configurer). -pleaseSelectAnItemToMapTo=Sélectionnez un élément auquel mapper l'appareil. +deviceMappings=Mappages d''appareils +atMostOneEndOfTheTimeRangeMayBeOpen=Au moins une extrémité de l''intervalle de temps du mappage doit rester ouverte (ne pas configurer). +pleaseSelectAnItemToMapTo=Sélectionnez un élément auquel mapper l''appareil. device=Appareil timeRange=Intervalle de temps -closeTimeRange=Fermer extrémité ouverte de l'intervalle de temps -setClosingTimePoint=Définir une heure de fin pour l'intervalle de temps ouvert -startOfTimeRangeMustLieBeforeEnd=Le début de l'intervalle de temps doit se situer avant sa fin. +closeTimeRange=Fermer extrémité ouverte de l''intervalle de temps +setClosingTimePoint=Définir une heure de fin pour l''intervalle de temps ouvert +startOfTimeRangeMustLieBeforeEnd=Le début de l''intervalle de temps doit se situer avant sa fin. overallProgress=Progression générale eventOverview=Synthèse de la manifestation start=Départ @@ -1064,12 +1064,12 @@ showAddedScores=Afficher scores ajoutés pour chaque entrée du palmarès ratio=ratio importWind=Importer vent importWindTooltip=Si vous décochez cette option, cela réduira considérablement le volume de données transféré. -importDeviceConfigurations=Importer configurations de l'appareil -importDeviceConfigurationsTooltip=Si vous cochez cette option, TOUTES les configurations de l'appareil seront importées dans le serveur distant. -authorName=Nom de l'auteur -authorPriority=Priorité de l'auteur +importDeviceConfigurations=Importer configurations de l''appareil +importDeviceConfigurationsTooltip=Si vous cochez cette option, TOUTES les configurations de l''appareil seront importées dans le serveur distant. +authorName=Nom de l''auteur +authorPriority=Priorité de l''auteur removeDenotation=Supprimer marquage -competitorRegistrationsMissingProceed=Des inscriptions de concurrents sont manquantes pour au moins l'une des courses sélectionnées ({0}). Voulez-vous quand même continuer ? +competitorRegistrationsMissingProceed=Des inscriptions de concurrents sont manquantes pour au moins l''une des courses sélectionnées ({0}). Voulez-vous quand même continuer ? pleaseSelectAControlPoint=Sélectionnez un point de contrôle. twoMarkControlPoint=Point de contrôle à deux marques registeredCompetitors=Concurrents inscrits @@ -1085,10 +1085,10 @@ availableLeaderboardGroups=Groupes de palmarès disponibles leaderboardGroupsOfSelectedEvent=Groupe de palmarès affectés à la manifestation addRaces=Ajouter des courses withNamePrefix=avec préfixe de nom -pleaseSelectASeriesFirst=Sélectionnez d'abord une série. +pleaseSelectASeriesFirst=Sélectionnez d''abord une série. upcommingEventStartsInDays=dans {0,number} jours upcommingEventStartsInDays[one]=demain -upcommingEventStartsInDays[none]=aujourd'hui +upcommingEventStartsInDays[none]=aujourd''hui sharingMailTooltip=Partager par e-mail sharingTwitterTooltip=Partager sur Twitter sharingFacebookTooltip=Partager sur Facebook @@ -1097,7 +1097,7 @@ eventSharingShortText={0} dans {1} le {2} #String eventSharingLongText(String eventName, String venue, String dateString, String url); eventSharingLongText=Je voudrais partager {0} dans {1} le {2}. Détails : \n{3} #String seriesSharingLongText(String seriesName, String url); -seriesSharingLongText=J'aimerai partager la série {0}. Détails : {1} +seriesSharingLongText=J''aimerai partager la série {0}. Détails : {1} #String seriesSharingShortText(String seriesName); seriesSharingShortText={0} competitorsAnalytics=Analyse des concurrents @@ -1108,11 +1108,11 @@ videos=Vidéos image=Image images=Images video=Vidéo -flagImageURL=URL d'image de pavillon (résolution d'image à 18x12px) -imageURLs=URL d'image +flagImageURL=URL d''image de pavillon (résolution d''image à 18x12px) +imageURLs=URL d''image videoURLs=URL de vidéo -sponsorImageURLs=URL d'image du sponsor -invalidSelection=La sélection actuelle n'est pas valide. +sponsorImageURLs=URL d''image du sponsor +invalidSelection=La sélection actuelle n''est pas valide. advancePassId=ID de passage avancé pleaseSelectAScoringResult=Sélectionnez un résultat... timeZone=Fuseau horaire @@ -1120,30 +1120,30 @@ eventOfficialWebsiteURL=URL du site Web officiel eventBaseURL=URL de base de la manifestation (http://something.sapsailing.com) eventSailorsInfoWebsiteURL=URL du site Web avec infos pour les concurrents eventOverviewURL=URL de synthèse de la manifestation -eventLogoImageURL=URL de l'image du logo +eventLogoImageURL=URL de l''image du logo showPingMarkMappings=Afficher mappages pour marques avec pings effectués regattaNameMustNotContainSlashes=Le nom de la régate ne doit pas contenir de barres obliques. showNumberOfRacesScored=Nombre de courses avec points -errorFetchingWindStreamletData=Erreur lors de l'accès aux données du couloir de vent : {0} +errorFetchingWindStreamletData=Erreur lors de l''accès aux données du couloir de vent : {0} showWindStreamletOverlay=Afficher superposition des couloirs de vent showWindStreamletColors=Colorer les couloirs de vent en fonction de sa vitesse showSimulationOverlay=Afficher superposition de la simulation -simulationLegendTooltip=Comparaison des temps : \nCourse désigne la durée de la portion de parcours mesurée à l'aide d'un GPS, Omniscient désigne la course dans le cas où l'on a toutes les données du vent, Opportuniste désigne la course dans le cas où l'on décide de virer de bord en mesurant la distance jusqu'à la marque suivante, Virement de bord unique désigne les courses dans le cas où l'on a toutes les données du vent et l'on décide de virer de bord une seule fois. +simulationLegendTooltip=Comparaison des temps : \nCourse désigne la durée de la portion de parcours mesurée à l''aide d''un GPS, Omniscient désigne la course dans le cas où l''on a toutes les données du vent, Opportuniste désigne la course dans le cas où l''on décide de virer de bord en mesurant la distance jusqu''à la marque suivante, Virement de bord unique désigne les courses dans le cas où l''on a toutes les données du vent et l''on décide de virer de bord une seule fois. racesScored=Courses avec points racesScoredTooltip=Nombre de courses que le concurrent a terminées, ou pour lesquelles il a obtenu un score au palmarès. -averageNumberOfOperationsPerMessage=Nombre moyen d'opérations par message +averageNumberOfOperationsPerMessage=Nombre moyen d''opérations par message showUncorrectedTotalPoints=Afficher total des points non corrigé setStartTimeReceived=Afficher heure de départ reçue -setStartTimeReceivedDescription=Définit l'heure de départ reçue de la course suivie sélectionnée non persistante. Cela signifie que la nouvelle valeur sera oubliée une fois que le serveur sera relancé. +setStartTimeReceivedDescription=Définit l''heure de départ reçue de la course suivie sélectionnée non persistante. Cela signifie que la nouvelle valeur sera oubliée une fois que le serveur sera relancé. lastScoreCorrectionsTime=Dernière heure de correction du score lastScoreCorrectionsComment=Dernier commentaire sur la correction du score setTimeToNow=Définir heure sur "maintenant" -useStartTimeInference=Utiliser l'interférence temporelle des passages des marques de départ -controlTrackingFromStartAndFinishTimes=Contrôler suivi à partir des heures de départ et d'arrivé -numberOfQueueMessagesSent=Nombre de messages en file d'attente envoyés +useStartTimeInference=Utiliser l''interférence temporelle des passages des marques de départ +controlTrackingFromStartAndFinishTimes=Contrôler suivi à partir des heures de départ et d''arrivé +numberOfQueueMessagesSent=Nombre de messages en file d''attente envoyés totalSize=Taille totale averageMessageSize=Taille moyenne par message en octets -totalNumberOfOperations=Nombre total d'opérations +totalNumberOfOperations=Nombre total d''opérations currentOrAverageSpeedOverGroundInKnotsTooltip=Vitesse fond actuelle en nœuds sur une portion de parcours en cours ; vitesse fond moyenne lorsque la portion de parcours est terminée. currentOrAverageSpeedOverGroundInKnots=Vf (∅ à la fin) connectors=Connecteurs @@ -1175,16 +1175,16 @@ advanced=Avancé basedOn=basé sur retrieveWith=Récupérer avec mappingDetails=Détails du mappage -deviceMappingQrCodeExplanation=Si vous utilisez l'application de suivi, vous pouvez également ajouter le mappage de l'appareil en sélectionnant un concurrent/une marque, en définissant des heures de départ et d'arrivée et en scannant ce code QR. +deviceMappingQrCodeExplanation=Si vous utilisez l''application de suivi, vous pouvez également ajouter le mappage de l''appareil en sélectionnant un concurrent/une marque, en définissant des heures de départ et d''arrivée et en scannant ce code QR. qrCode=Code QR enterCourseAreaName=Saisissez le nom de la zone de course... enterCourseName=Saisissez le nom de la course... -enterImageURL=Saisissez l'URL de l'image... -enterVideoURL=Saisissez l'URL de la vidéo... -enterSponsorImageURL=Saisissez l'URL de l'image du sponsor... +enterImageURL=Saisissez l''URL de l''image... +enterVideoURL=Saisissez l''URL de la vidéo... +enterSponsorImageURL=Saisissez l''URL de l''image du sponsor... enterRaceName=Saisissez le nom du parcours... -serverError=Une erreur s'est produite lors de la tentative de contact du serveur. Vérifiez la connexion réseau et réessayez. -remoteProcedureCall=Procédure d'appel distante +serverError=Une erreur s''est produite lors de la tentative de contact du serveur. Vérifiez la connexion réseau et réessayez. +remoteProcedureCall=Procédure d''appel distante serverReplies=Réponses du serveur errorCommunicatingWithServer=Erreur lors de la communication avec le serveur userManagement=Gestion des utilisateurs @@ -1200,7 +1200,7 @@ autoplaySettings=Options de lecture automatique startBrowserFullscreen=Lancer navigateur en mode plein écran switchToLiveRaceAutomatically=Passer automatiquement à la course en direct timeBeforeRaceStart=durée avant le départ de la course (en secondes) -errorTryingToGetEvents=Erreur lors de la tentative d'accès aux manifestations : {0} +errorTryingToGetEvents=Erreur lors de la tentative d''accès aux manifestations : {0} showXYDiagram=Afficher diagramme x-y xyDiagram=Diagramme x-y boatSpeed=Vitesse du bateau @@ -1211,41 +1211,41 @@ errorTryingToCreateNewEvent=Erreur lors de la tentative de création de la nouve createNewEvent=Créer manifestation noFleetsDefined=Aucune flotte définie successfullyCreatedRegattas=Création des régates réussie -errorTryingToRegisterRacesForTracking=Erreur lors de la tentative d'enregistrement des courses {0} pour le suivi : {1}. Vérifiez la syntaxe de l'URL stockée/du direct. +errorTryingToRegisterRacesForTracking=Erreur lors de la tentative d''enregistrement des courses {0} pour le suivi : {1}. Vérifiez la syntaxe de l''URL stockée/du direct. errorDeterminingPolarAvailability=Erreur lors de la détermination de la disponibilité des données polaires/VPP pour la course {0} : {1} error=Erreur fileStorage=Stockage du fichier active=Actif -scoringSchemeHighPointEssOverallDescription=Score en points. Le vainqueur d'un Act totalise 10 points, le 2e - 9 points, etc. En cas d'égalité au classement général des Extreme Sailing Series, la victoire est accordée au concurrent ayant remporté le plus d'Act. Si l'égalité persiste, le résultat obtenu au dernier Act sera utilisé. +scoringSchemeHighPointEssOverallDescription=Score en points. Le vainqueur d''un Act totalise 10 points, le 2e - 9 points, etc. En cas d''égalité au classement général des Extreme Sailing Series, la victoire est accordée au concurrent ayant remporté le plus d''Act. Si l''égalité persiste, le résultat obtenu au dernier Act sera utilisé. timeBetweenRaceStartAndCompetitorStartInSeconds=Décalage avec le départ timeBetweenRaceStartAndCompetitorStartInSecondsTooltip=Durée écoulée entre le départ de la course et le moment auquel le concurrent a passé le point de cheminement du départ. Une durée négative suggère un OCS (départ prématuré). useInternalAlgorithm=Utiliser algorithme de passage de marque interne editMarkPassings=Modifier passages des marques editMarkPositions=Modifier positions des marques removeFixedPassings=Supprimer passage de marque fixé -setFixedPassing=Définir l'heure comme passage de marque +setFixedPassing=Définir l''heure comme passage de marque setSuppressedPassing=Supprimer passage de marque en commençant par marque actuelle removeSuppressedPassing=Supprimer passage de marque supprimé -warningSettingFixedPassing=L'heure à laquelle le point de cheminement {0} a été passé ne peut pas être antérieure à l'heure de passage du point de cheminement précédent, ni postérieure à l'heure de passage du point de cheminement suivant. +warningSettingFixedPassing=L''heure à laquelle le point de cheminement {0} a été passé ne peut pas être antérieure à l''heure de passage du point de cheminement précédent, ni postérieure à l''heure de passage du point de cheminement suivant. errorRemovingFixedPassing=Erreur lors de la suppression du passage de marque fixé : {0} errorSettingFixedPassing=Erreur lors de la définition du passage de marque fixé : {0} errorSuppressingPassing=Erreur lors de la suppression des passages de marques : {0} errorRemovingSupressedPassing=Erreur lors de la suppression des passages de marques supprimés : {0} -errorTryingToObtainMarkPassing=Erreur lors de la tentative d'obtention des passages de marques : {0} -errorTryingToObtainRaceLogMarkPassingData=Erreur lors de la tentative d'obtention des données de passages de marques du journal de course : {0} +errorTryingToObtainMarkPassing=Erreur lors de la tentative d''obtention des passages de marques : {0} +errorTryingToObtainRaceLogMarkPassingData=Erreur lors de la tentative d''obtention des données de passages de marques du journal de course : {0} email=E-mail pleaseEnterAnEmail=Saisissez un e-mail. inviteCompetitors=Inviter des concurrents inviteSelectedCompetitors=Inviter concurrents sélectionnés -notAllCompetitorsProvideEmail=Les concurrents n'ont pas tous fourni un e-mail. -sendingMailsFailed=Échec de l'envoi des e-mails +notAllCompetitorsProvideEmail=Les concurrents n''ont pas tous fourni un e-mail. +sendingMailsFailed=Échec de l''envoi des e-mails sendingMailsSuccessful=Envoi des e-mails réussi -selectEventForInvitation=Sélectionnez une manifestation pour l'invitation. -imageURL=URL d'image +selectEventForInvitation=Sélectionnez une manifestation pour l''invitation. +imageURL=URL d''image upload=Charger removeResult=Supprimer opération : {0} {1} uploadSuccessful=Chargement réussi -fileUploadResult=Chargement du fichier : {0} {1}.\nEn cas d'erreur, vérifiez que votre service de stockage de fichier est correctement configuré. +fileUploadResult=Chargement du fichier : {0} {1}.\nEn cas d''erreur, vérifiez que votre service de stockage de fichier est correctement configuré. removeUploadedFile=Supprimer fichier chargé showCompetitorSailIdColumn=ID de voile showCompetitorFullNameColumn=Nom complet du concurrent @@ -1256,15 +1256,15 @@ orMultipleEmails=ou plusieurs adresses e-mails séparées par des virgules courseOverGroundTrueDegreesTooltip=Route fond vraie en degrés courseOverGroundTrueDegrees=Route fond distanceIncludingGateStartInMeters=Distance (si départ au lièvre) -distanceTraveledIncludingGateStartTooltip=La distance naviguée du départ de la portion de parcours jusqu'à sa fin\nou jusqu'à l'heure actuelle (si la portion de parcours n'est pas terminée).\nSi la portion de parcours inclut un départ au lièvre, la distance de la bouée de ligne jusqu'à la position de départ est incluse \npour permettre de comparer les concurrents même si leur départ ne s'est pas fait à la même heure. -raceDistanceTraveledIncludingGateStartTooltip=La distance naviguée du départ de la course jusqu'à sa fin\nou jusqu'à l'heure actuelle (si la course n'est pas terminée).\nEn cas de départ au lièvre, la distance de la bouée de ligne jusqu'à la position de départ est incluse \npour permettre de comparer les concurrents même si leur départ ne s'est pas fait à la même heure. +distanceTraveledIncludingGateStartTooltip=La distance naviguée du départ de la portion de parcours jusqu''à sa fin\nou jusqu''à l''heure actuelle (si la portion de parcours n''est pas terminée).\nSi la portion de parcours inclut un départ au lièvre, la distance de la bouée de ligne jusqu''à la position de départ est incluse \npour permettre de comparer les concurrents même si leur départ ne s''est pas fait à la même heure. +raceDistanceTraveledIncludingGateStartTooltip=La distance naviguée du départ de la course jusqu''à sa fin\nou jusqu''à l''heure actuelle (si la course n''est pas terminée).\nEn cas de départ au lièvre, la distance de la bouée de ligne jusqu''à la position de départ est incluse \npour permettre de comparer les concurrents même si leur départ ne s''est pas fait à la même heure. results=Résultats groupName=Nom du groupe valueAscending=Valeur (ascendant) valueDescending=Valeur (descendant) sortBy=Trier par dashboardHeader=Tableau de bord -dashboardNoWindBotAvailableHeader=Le bot du vent n'est pas disponible. +dashboardNoWindBotAvailableHeader=Le bot du vent n''est pas disponible. dashboardNoWindBotAvailableMessage=Pour pouvoir recevoir des données de vent depuis des unités de mesure du vent, assurez-vous que le bot du vent est allumé et connecté à SAP Sailing Analytics. dashboardWindBot=Bot du vent dashboardTrueWindSpeed=Vitesse vent réel @@ -1274,16 +1274,16 @@ dashboardTrueWindDirectionUnit=deg dashboardLiveWind=en direct dashboardAverageWind=moyenne dashboardAverageWindMinutes=({0} minutes) -dashboardWindChartHint=Touchez le graphique pour modifier l'intervalle. +dashboardWindChartHint=Touchez le graphique pour modifier l''intervalle. dashboardSelectCompetitor=Sélectionner concurrent dashboardStartAnalysesHeader=Analyses de départ dashboardNewStartAnalysisAvailable=Nouvelle analyse de départ disponible dashboardNoStartAnalysesAvailableHeader=Aucune analyse de départ disponible -dashboardNoStartAnalysesAvailableMessage=Une analyse de départ est créée à partir de chaque départ de course. Veuillez patienter jusqu'à ce que la course commence. -dashboardNoStartlineAdvantagesByWindAvailableHeader=Aucun avantage de ligne de départ n'est disponible. -dashboardNoStartlineAdvantagesByWindAvailableMessage=Pour pouvoir calculer l'avantage de la ligne de départ, un parcours doit être défini par le comité de course. -dashboardNoStartlineAdvantagesByGeometryAvailableHeader=Aucun avantage de ligne de départ n'est disponible. -dashboardNoStartlineAdvantagesByGeometryAvailableMessage=Pour pouvoir calculer l'avantage de la ligne de départ, un parcours doit être défini par le comité de course. +dashboardNoStartAnalysesAvailableMessage=Une analyse de départ est créée à partir de chaque départ de course. Veuillez patienter jusqu''à ce que la course commence. +dashboardNoStartlineAdvantagesByWindAvailableHeader=Aucun avantage de ligne de départ n''est disponible. +dashboardNoStartlineAdvantagesByWindAvailableMessage=Pour pouvoir calculer l''avantage de la ligne de départ, un parcours doit être défini par le comité de course. +dashboardNoStartlineAdvantagesByGeometryAvailableHeader=Aucun avantage de ligne de départ n''est disponible. +dashboardNoStartlineAdvantagesByGeometryAvailableMessage=Pour pouvoir calculer l''avantage de la ligne de départ, un parcours doit être défini par le comité de course. dashboardStartlineAdvantagesByWindHeader=Avantages de ligne de départ par vent dashboardStartlineAdvantageByGeometryHeader=Avantage de ligne de départ par géométrie dashboardRankAtFirstMark=Place à la première marque @@ -1303,12 +1303,12 @@ currentFilterSelection=Sélection du filtre actuel notCapableOfGeneratingACodeForIdentifier=Je ne suis pas capable de générer un code pour cet identifiant. serverUrl=URL du serveur rotatedFromTrueNorth=Pivoté de {0} degrés à partir du vrai Nord. -clickToToggleWindUp=Touchez/Cliquez pour basculer entre l'affichage orienté nord et l'affichage par rapport au sens du vent +clickToToggleWindUp=Touchez/Cliquez pour basculer entre l''affichage orienté nord et l''affichage par rapport au sens du vent clickToToggleWindStreamlets=Touchez/cliquez pour afficher ou masquer les couloirs de vent. startLineToFirstMarkTriangle=Distance entre le départ et la première marque ({0} m) -dataMiningComponentsHaveBeenUpdated=Les composants d'exploration de données ont été mis à jour. -dataMiningComponentsNeedReloadDialogMessage=Cliquez sur Recharger pour recharger les composants maintenant. Les données actuellement affichées seront ignorées et une requête par défaut sera exécutée.n\Cliquez sur Fermer pour ne rien faire. L'exploration de données ne fonctionnera pas correctement tant que les composants n'auront pas été rechargés. -noDataForEvent=Il n'y a pas encore de données pour cette manifestation. +dataMiningComponentsHaveBeenUpdated=Les composants d''exploration de données ont été mis à jour. +dataMiningComponentsNeedReloadDialogMessage=Cliquez sur Recharger pour recharger les composants maintenant. Les données actuellement affichées seront ignorées et une requête par défaut sera exécutée.n\Cliquez sur Fermer pour ne rien faire. L''exploration de données ne fonctionnera pas correctement tant que les composants n''auront pas été rechargés. +noDataForEvent=Il n''y a pas encore de données pour cette manifestation. countriesCount={0,number} pays countriesCount[one]={0,number} pays racesCount={0,number} courses @@ -1327,7 +1327,7 @@ matcher=Comparateur any=Tout urlProviders=Fournisseurs de résultats basés sur une URL pleaseSelectAURLProvider=Sélectionnez un fournisseur de résultat basé sur une URL… -sampleURL=Exemple d'URL : {0} +sampleURL=Exemple d''URL : {0} sapSportsOn=SAP Sports sur followSapSports=Suivre SAP Sports liveNow=En direct @@ -1348,9 +1348,9 @@ rankingMetric=Classement oneDesignRankingMetric=Monotype  orcPerformanceCurveRankingMetric=Courbe de performance ORC timeOnTimeAndDistanceRankingMetric=Temps sur temps/Temps sur distance -oneDesignRankingMetricDescription=Monotype : le vainqueur est le premier à franchir la ligne.\nLe classement se base sur les positions au vent (dans le lit du vent/vent arrière) ou en fonction de la position dans la course (jusqu'à atteindre un point). -orcPerformanceCurveRankingMetricDescription=Courbe de performance ORC : procédé de distribution des handicaps sophistiqué qui accorde des compensations de temps en fonction d'un VPP/polaire, en imaginant des angles de portions de parcours prédéfinis par rapport au vent.\nEn fonction de ces compensations, un "vent implicite" est calculé et sert de base au classement.\nLe vent implicite peut être calculé à n'importe quel moment dans la course et sert alors de base pour le classement dans la course. -timeOnTimeAndDistanceRankingMetricDescription=Temps sur temps/Temps sur distance : classement final par temps calculé ;\nle temps est calculé en appliquant, de façon facultative, un facteur au temps réel (1.0 par défaut)\net en soustrayant une compensation en secondes par mille marin,\nappliqué à la longueur de la course.\nLe classement est effectué sur la base de l'arrivée estimée selon la position actuelle du bateau le plus rapide\nen supposant le VMG/VMC moyen. +oneDesignRankingMetricDescription=Monotype : le vainqueur est le premier à franchir la ligne.\nLe classement se base sur les positions au vent (dans le lit du vent/vent arrière) ou en fonction de la position dans la course (jusqu''à atteindre un point). +orcPerformanceCurveRankingMetricDescription=Courbe de performance ORC : procédé de distribution des handicaps sophistiqué qui accorde des compensations de temps en fonction d''un VPP/polaire, en imaginant des angles de portions de parcours prédéfinis par rapport au vent.\nEn fonction de ces compensations, un "vent implicite" est calculé et sert de base au classement.\nLe vent implicite peut être calculé à n''importe quel moment dans la course et sert alors de base pour le classement dans la course. +timeOnTimeAndDistanceRankingMetricDescription=Temps sur temps/Temps sur distance : classement final par temps calculé ;\nle temps est calculé en appliquant, de façon facultative, un facteur au temps réel (1.0 par défaut)\net en soustrayant une compensation en secondes par mille marin,\nappliqué à la longueur de la course.\nLe classement est effectué sur la base de l''arrivée estimée selon la position actuelle du bateau le plus rapide\nen supposant le VMG/VMC moyen. timeOnTimeFactor=Facteur temps sur temps (ToT) timeOnDistanceAllowanceInSecondsPerNauticalMile=Compensation temps sur distance (ToD) timeOnTimeFactorTooltip=Facteur temps sur temps ; le temps réel est multiplié par ce facteur dans la formule de temps calculé. @@ -1358,7 +1358,7 @@ timeOnDistanceAllowanceInSecondsPerNauticalMileTooltip=Compensation temps sur di calculatedTimeTraveled=Temps calculé calculatedTimeTraveledTooltip=Temps calculé selon le handicap du concurrent \nbasé sur le temps à partir du départ de la course et de la distance parcourue (au vent). raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSeconds=Temps calculé @ par rapport au plus rapide -raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Temps calculé selon l'arrivée estimée du concurrent qui est actuellement en tête de la course ; \nestimation basée sur la VMG dans la portion de parcours actuelle, équivaut à la performance (calculée) du bateau le plus rapide dans toutes les portions de parcours suivantes. +raceCalculatedTimeAtEstimatedArrivalAtCompetitorFarthestAheadInSecondsTooltip=Temps calculé selon l''arrivée estimée du concurrent qui est actuellement en tête de la course ; \nestimation basée sur la VMG dans la portion de parcours actuelle, équivaut à la performance (calculée) du bateau le plus rapide dans toutes les portions de parcours suivantes. sailorInfo=Informations concurrents sailorInfoLongText=Résultats officiels, réclamations, météo marine eventQuickfinder=Quickfinder manifestation @@ -1368,7 +1368,7 @@ racesQuickfinder=Quickfinder courses profileQuickfinder=Quickfinder profil statistics=Statistiques impressions=Impressions -notAvailableOnMobileMessage=Ce contenu n'existe pas en version mobile. \nPasser à la version bureau ? +notAvailableOnMobileMessage=Ce contenu n''existe pas en version mobile. \nPasser à la version bureau ? gotoDesktop=Aller à la version bureau goBack=Retour showAllX=Afficher tout {0} @@ -1380,7 +1380,7 @@ numberWindFixes=Points vent sailedMiles=Milles navigués millionValue={0,number,#0.0} mil billionValue={0,number,#0.0} bil -noResults=Aucun résultat disponible pour l'instant. +noResults=Aucun résultat disponible pour l''instant. noNews=Aucune actualité disponible. pointsValue={0,number,#0.00} openLeaderboard=Ouvrir palmarès @@ -1398,7 +1398,7 @@ courseGeometry=Géométrie du parcours degreesToWind={0}° au vent miniLeeaderboardLegendText=Affiche les points associés au nombre de courses par concurrent currentOfTotal={0,number}/{1,number} -noFinishedRaces=Aucune course terminée pour l'instant. +noFinishedRaces=Aucune course terminée pour l''instant. racesOverview=Synthèse des courses listFormatLabel=Format de liste competitionFormatLabel=Format de compétition @@ -1421,7 +1421,7 @@ eventsHaveTakenPlace={0} manifestations ont eu lieu. eventsHaveTakenPlace[one]=Une manifestation a eu lieu. raceOffice=Bureau de course analyze=Analyser -dataMiningSettings=Options de l'exploration de données +dataMiningSettings=Options de l''exploration de données multiResultsPresenter=Visualiseur de résultats multiples plainResultsPresenter=Visualiseur de résultats bruts resultsChart=Graphique des résultats @@ -1448,28 +1448,28 @@ resultsFoundForSearch={0,number} résultats trouvés pour ''{1}'' resultsFoundForSearch[one]={0,number} résultat trouvé pour ''{1}'' runPredefinedQuery=Exécuter requête prédéfinie selectPredefinedQuery=Sélectionner requête prédéfinie -predefinedQueryRunner=Outil d'exécution de requêtes prédéfinies +predefinedQueryRunner=Outil d''exécution de requêtes prédéfinies developerOptions=Options développeur copyToClipboard=Copier dans le presse-papiers code=Code useClassGetName=Utilisez Class.getName() pour les noms des types. -useClassGetNameTooltip=Plus stable face aux modifications dans la base de code, mais le fichier de script peut uniquement être utilisé dans l'étendue où les classes sont disponibles. +useClassGetNameTooltip=Plus stable face aux modifications dans la base de code, mais le fichier de script peut uniquement être utilisé dans l''étendue où les classes sont disponibles. useStringLiterals=Utiliser littéraux de chaîne pour les noms de types useStringLiteralsTooltip=Le fichier de script peut être utilisé partout, mais sera corrompu si la base de code change. errorLoadingDataWithTryAgain=Erreur lors du chargement des données. Nouvel essai dans quelques minutes. addGalleryPhoto=Ajouter photo de la galerie -addStageImage=Ajouter image d'étape -addTeaserImage=Ajouter image d'accroche +addStageImage=Ajouter image d''étape +addTeaserImage=Ajouter image d''accroche addEventLogo=Ajouter logo de la manifestation noImagesDefinedYet=Aucune image définie pour le moment -imageSizeError=La taille de l'image {0} ne correspond pas. La largeur doit être comprise entre {1} et {2} pixels et la hauteur entre {3} et {4} pixels. -couldNotRetrieveImageSizeYet=Impossible de récupérer la largeur et la hauteur de l'image pour l'instant -pleaseOnlyUploadContentYouHaveAllUsageRightsFor=Chargez uniquement le contenu pour lequel vous avez toutes les autorisations d'utilisation. Notez que le contenu peut être rogné. +imageSizeError=La taille de l''image {0} ne correspond pas. La largeur doit être comprise entre {1} et {2} pixels et la hauteur entre {3} et {4} pixels. +couldNotRetrieveImageSizeYet=Impossible de récupérer la largeur et la hauteur de l''image pour l''instant +pleaseOnlyUploadContentYouHaveAllUsageRightsFor=Chargez uniquement le contenu pour lequel vous avez toutes les autorisations d''utilisation. Notez que le contenu peut être rogné. registerCompetitorsOnRace=Inscrire concurrents pour la course (par exemple pour une course avec division de flotte) doYouWantToRegisterCompetitorsDirectlyOnTheRace=Voulez-vous inscrire les concurrents directement pour la course ? -doYouWantToDisableCompetitorsRegistrationsOnTheRace=Voulez-vous désactiver l'inscription des concurrents pour la course ? -warningDirectCompetitorRegistration=Avertissement : cette option engendrera l'inscription des concurrents de cette course séparément à chaque course. Si les concurrents sont inscrits à une régate, ils ne seront pas automatiquement inscrits à cette course. -warningRegattaCompetitorRegistration=Avertissement : ceci réactivera l'inscription des concurrents à la régate. Toutes les inscriptions à la régate seront automatiquement utilisées comme inscriptions à cette course. +doYouWantToDisableCompetitorsRegistrationsOnTheRace=Voulez-vous désactiver l''inscription des concurrents pour la course ? +warningDirectCompetitorRegistration=Avertissement : cette option engendrera l''inscription des concurrents de cette course séparément à chaque course. Si les concurrents sont inscrits à une régate, ils ne seront pas automatiquement inscrits à cette course. +warningRegattaCompetitorRegistration=Avertissement : ceci réactivera l''inscription des concurrents à la régate. Toutes les inscriptions à la régate seront automatiquement utilisées comme inscriptions à cette course. competitorRegistrationsOnRaceDisabled=Les inscriptions des concurrents sont désactivées pour cette course. Pour les activer, cochez la case sur la gauche. warningForDisabledCompetitors=Les concurrents suivants ne peuvent pas être inscrits à cette course : {0} competitorToolTipMessage={0} a déjà été affecté à la flotte {2} dans la course {3} et ne peut donc pas être affecté à la flotte {1} dans la même course. @@ -1480,22 +1480,22 @@ requiresValidRegatta=Pour identifier la course à afficher, cette page nécessit couldNotObtainRace=Impossible de trouver une course ayant le nom {1} pour la flotte {2} pour une régate ayant le nom {0} : {3} errorTryingToCreateEmbeddedMap=Erreur lors de la tentative de création de la carte intégrée : {0} topN={0} meilleurs -transparentBufferLineOnHover=Lignes tampons transparentes lors du passage du curseur au-dessus des lignes d'aide +transparentBufferLineOnHover=Lignes tampons transparentes lors du passage du curseur au-dessus des lignes d''aide bufferLineStrokeWeight=Épaisseur de la ligne tampon profile=Profil showOnlyCompetitorsOfLog=Afficher uniquement concurrents inscrits dans le journal confirmLosingCompetitorEditsWhenTogglingLogBasedView=Cette action réinitialisera les modifications non enregistrées apportées aux concurrents.\nVoulez-vous vraiment continuer ? removalOfMarkDisabledMayBeUsedInRaces=Suppression désactivée, marques utilisées dans les courses {0} createDefaultLeaderboardGroup=Voulez-vous créer un groupe de palmarès par défaut pour votre manifestation ? -pleaseCreateAtLeastOneMappingBy=Créez au moins un mappage en sélectionnant d'abord une piste sur la gauche, puis une marque ou un concurrent sur la droite. +pleaseCreateAtLeastOneMappingBy=Créez au moins un mappage en sélectionnant d''abord une piste sur la gauche, puis une marque ou un concurrent sur la droite. matcherType=Type de comparateur matchingDevices=Appareils correspondants addDevice=Ajouter appareil -createDeviceConfiguration=Créer configuration d'appareil -forWhichDeviceShouldConfigurationApply=Indiquez l'appareil auquel la configuration doit s'appliquer. +createDeviceConfiguration=Créer configuration d''appareil +forWhichDeviceShouldConfigurationApply=Indiquez l''appareil auquel la configuration doit s''appliquer. create=Créer thereIsAlreadyAConfigurationForThisDevice=Une configuration existe déjà pour cet appareil. -enterDeviceIdentifierName=Saisissez un nom d'identifiant. +enterDeviceIdentifierName=Saisissez un nom d''identifiant. administration=Administration pleaseSelectALeaderboardGroup=Sélectionnez un groupe de palmarès. linkLeaderboardToLeaderboardGroupOfEvent=Liez le palmarès au groupe de palmarès de la manifestation. @@ -1504,11 +1504,11 @@ failedToLinkLeaderboardToLeaderboardGroup=La liaison du palmarès {0} au groupe createDefaultRegatta=Créer régate par défaut doYouWantToCreateADefaultRegatta=Voulez-vous créer une régate par défaut ? defaultLocale=Par défaut -defaultSailorsInfoLinkInfoText=Le système utilise le lien par défaut, sauf si une version spécifique de la langue existe. Si aucun lien par défaut n'existe, aucun lien n'est associé aux langues pour lesquelles aucun lien spécifique n'a été défini. +defaultSailorsInfoLinkInfoText=Le système utilise le lien par défaut, sauf si une version spécifique de la langue existe. Si aucun lien par défaut n''existe, aucun lien n''est associé aux langues pour lesquelles aucun lien spécifique n''a été défini. qrSync=Synchronisation code QR -thereIsNoIdentifierSet=Aucun identifiant n'est défini. -couldNotObtainAccessTokenForUser=Impossible d'obtenir un jeton d'accès pour l'utilisateur {0} -raceManagerDeviceName=Nom de l'appareil +thereIsNoIdentifierSet=Aucun identifiant n''est défini. +couldNotObtainAccessTokenForUser=Impossible d''obtenir un jeton d''accès pour l''utilisateur {0} +raceManagerDeviceName=Nom de l''appareil serverURLInvalid=Saisissez une URL de serveur valide. serverURLEmpty=URL de serveur vide marks=Marques @@ -1516,7 +1516,7 @@ addNewFix=Ajouter nouveau point pleaseSelectOtherTimepoint=Sélectionnez un autre point dans le temps. Il existe déjà un point pour le point dans le temps du curseur de temps. confirmMove=Confirmer déplacement confirmNewFix=Confirmer nouveau point -selectAFixPositionBy=Sélectionnez une position de point en faisant glisser la carte. Ensuite, confirmez ou annulez à l'aide des boutons ci-dessous. +selectAFixPositionBy=Sélectionnez une position de point en faisant glisser la carte. Ensuite, confirmez ou annulez à l''aide des boutons ci-dessous. pleaseSelectAMark=Sélectionnez une marque dans la liste sur la gauche. markFixes=Points de marques playstoreCampaign=utm_source=sapsailing&utm_medium=solutions&utm_content=2016.02&utm_campaign=solutions&pcampaignid=2016.sapsailing.solutions @@ -1529,7 +1529,7 @@ appstoreBadgeSuffix=_fr distanceFromAveragePosition=Distance de la position moyenne useATouchOptimizedUI=Utilisez une interface utilisateur tactile optimisée pour déplacer le point. deleteFix=Supprimer point -theDeletionOfThisFix=La suppression de ce point n'est pas possible actuellement. +theDeletionOfThisFix=La suppression de ce point n''est pas possible actuellement. loadingMarkFixes=Chargement de points de marques... fixSuccessfullyAdded=Ajout du point réussi. fixPositionSuccessfullyEdited=Modification de la position du point réussie. @@ -1537,9 +1537,9 @@ fixSuccessfullyRemoved=Suppression du point réussie. dragToChangePosition=Glissez pour modifier la position.\nClic droit pour ouvrir le menu permettant la suppression. moveFix=Déplacer point manage2SailEvent=Manifestation Manage2Sail -noEventsYet=Aucune manifestation pour l'instant. -selectCompetitorImportProvider=Sélectionnez un fournisseur d'importation de concurrents... -selectResultImportProvider=Sélectionnez un fournisseur d'importation de résultats... +noEventsYet=Aucune manifestation pour l''instant. +selectCompetitorImportProvider=Sélectionnez un fournisseur d''importation de concurrents... +selectResultImportProvider=Sélectionnez un fournisseur d''importation de résultats... buildVersion=Version de build serverInformation=Informations serveur serverConfiguration=Configuration du serveur @@ -1557,9 +1557,9 @@ init=Initialisation... connectionSetup=Établissement de la connexion connectionEstablish=Connexion en cours... transferStarted=Lecture des données -transferCompleted=Transfert des données terminé. Initialisation de l'opération d'importation. -importInit=Initialisation de l'importation -importWait=En attente de la fin d'autres opérations d'importation +transferCompleted=Transfert des données terminé. Initialisation de l''opération d''importation. +importInit=Initialisation de l''importation +importWait=En attente de la fin d''autres opérations d''importation importLeaderboardGroups=Importation de groupes de palmarès en cours... importWindTracks=Importation de pistes de vent en cours... importSensorFixes=Importation de points capteurs en cours... @@ -1602,7 +1602,7 @@ simulationLegendMixedLegText=Vent ambigu noTracksFound=Aucun suivi trouvé noRacesAvailable=Aucune course disponible loadingRegattasAndRaces=Chargement de régates et de courses -selectFromRacesWithOverlappingTimeRange=Sélectionnez parmi les courses dont l'intervalle de temps de la piste média se chevauche avec l'intervalle des courses auxquelles la piste doit être liée. +selectFromRacesWithOverlappingTimeRange=Sélectionnez parmi les courses dont l''intervalle de temps de la piste média se chevauche avec l''intervalle des courses auxquelles la piste doit être liée. finishTime=Arrivée à : {0} showCompetitorCharts=Afficher graphique de concurrents showWindChart=Afficher graphique du vent @@ -1618,30 +1618,30 @@ currentRideHeightInMeters=Hauteur pendant le planing currentRideHeightInMetersTooltip=Hauteur actuelle de planing currentOrAverageRideHeightInMeters=Hauteur pendant le planing (∅ à la fin) currentOrAverageRideHeightInMetersTooltip=Hauteur actuelle de planing en mètres avec la portion de parcours toujours en cours. Hauteur de planing moyenne après la fin de la portion de parcours. -pleaseCreateAtLeastOneMappingForCompetitor=Créez au moins un mappage en sélectionnant d'abord une piste sur la gauche, puis un concurrent sur la droite. +pleaseCreateAtLeastOneMappingForCompetitor=Créez au moins un mappage en sélectionnant d''abord une piste sur la gauche, puis un concurrent sur la droite. importAdditionalSensorData=Importer des données de capteurs supplémentaires watchLive=Regarder en direct raceAnalysis=Analyse de la course startAnalysis=Analyse du départ winningLanes=Voies gagnantes -maximumNumberOfDiscards=Nombre maximal d'éliminations +maximumNumberOfDiscards=Nombre maximal d''éliminations externalLinks=Liens externes urlForAllLanguages=URL pour toutes les langues urlForLanguage=URL pour la langue ''{0}'' notificationRegattaConfigurationUpdatedUsingByMarks=Configuration de régate active définie, en utilisant le concepteur de course « Par marques ». -warningOverrideRegattaConfigurationCourseDesignerToByMarks=La configuration de régate active existe déjà, mais avec l'option de concepteur de course erronée.\nSouhaitez-vous écraser l'option de concepteur de course et valider "Par marques" ? +warningOverrideRegattaConfigurationCourseDesignerToByMarks=La configuration de régate active existe déjà, mais avec l''option de concepteur de course erronée.\nSouhaitez-vous écraser l''option de concepteur de course et valider "Par marques" ? allRacesHaveBeenDenoted=Toutes les courses ont été marquées pour un suivi par journal de course. -chartSelectionHint=Astuce : Vous pouvez également utiliser le palmarès (sur l'onglet PALMARÈS) pour sélectionner les concurrents affichés dans le graphique. +chartSelectionHint=Astuce : Vous pouvez également utiliser le palmarès (sur l''onglet PALMARÈS) pour sélectionner les concurrents affichés dans le graphique. chooseALanguage=Sélectionner une langue solutions=Solutions blog=Blog officalEventWebsite=Site Web officiel de la manifestation -moreInfo=Plus d'infos +moreInfo=Plus d''infos viewAnalysis=Afficher analyses overallLeaderboard=Palmarès général pleaseTryAgain=Veuillez réessayer... reloadPage=Recharger la page -errorMessageLoadingData=Une erreur s'est produite pendant le chargement des données pour cette page. +errorMessageLoadingData=Une erreur s''est produite pendant le chargement des données pour cette page. regattaDetails=Détails de la régate chooseChartType=Sélectionnez le type de graphique. whatsNew=Nouveautés @@ -1671,7 +1671,7 @@ headerLogo=Sailing Analytics headerSearchPlaceholder=Rechercher mainEventShowAll=Afficher toutes les manifestations mainEventTitle=Manifestations les plus récentes du monde de la voile -mainMediaSubtitle=Oubliez le quotidien grâce à des images époustouflantes de l'édition la plus récente de votre manifestation de voile préférée. +mainMediaSubtitle=Oubliez le quotidien grâce à des images époustouflantes de l''édition la plus récente de votre manifestation de voile préférée. mainMediaTitle=Les photographes adorent la voile. mainMediaVideosSubtitle=Plongez dans le monde de la voile et accédez à encore plus de vidéos de nos manifestations les plus récentes. mainMediaVideosTitle=Vidéos récentes @@ -1687,11 +1687,11 @@ solutionsBuoyPingerHeadline=SAP Sailing Buoy Pinger solutionsPostHeadline=Analyses post-course solutionsSimulatorHeadline=Simulateur de stratégies sapInSailing=SAP in Sailing -contentSapInSailing1=Pour SAP, la voile est une plate-forme idéale pour présenter des solutions et permettre à la discipline d'atteindre une autre dimension. L'engagement de SAP dans cette discipline a transformé l'expérience de la voile grâce à des outils qui : +contentSapInSailing1=Pour SAP, la voile est une plate-forme idéale pour présenter des solutions et permettre à la discipline d''atteindre une autre dimension. L''engagement de SAP dans cette discipline a transformé l''expérience de la voile grâce à des outils qui : contentSapInSailing2=- aident les marins à analyser leur performance et à optimiser leur stratégie -contentSapInSailing3=- rapprochent les amateurs du feu de l'action -contentSapInSailing4=- mettent à disposition des médias des informations et des analyses permettant d'étoffer les commentaires qui accompagnent les manifestations -contentSapInSailing5=L'engagement de SAP dans le sport de la voile est de longue date, porte sur de nombreuses équipes et régates avec un portefeuille élargi qui comprend : +contentSapInSailing3=- rapprochent les amateurs du feu de l''action +contentSapInSailing4=- mettent à disposition des médias des informations et des analyses permettant d''étoffer les commentaires qui accompagnent les manifestations +contentSapInSailing5=L''engagement de SAP dans le sport de la voile est de longue date, porte sur de nombreuses équipes et régates avec un portefeuille élargi qui comprend : contentSapInSailing6=Partenaire technologique officiel de Travemünder Woche contentSapInSailing7=Partenaire technologique de la Ligue Européenne de Voile contentSapInSailing8=Sponsor principal du SAP Extreme Sailing Team @@ -1700,42 +1700,42 @@ contentSapInSailing10=Partenaire de la régate la plus grande au monde, Kieler W contentSapInSailing11=Partenaire technologique de la Sailing Champions League contentSapInSailing12=Sponsor principal de la compétition SAP 5O5 World Championships sapSailingAnalyticsTitle=SAP Sailing Analytics -contentSapSailingAnalytics1=Grâce aux analyses en temps réel des classements de course, vitesses, manœuvres, directions etc., SAP contribue à lever le mystère de la discipline complexe qu'est la voile, et à faciliter son approche. -contentSapSailingAnalytics2=Grâce aux analyses de la solution SAP Sailing Analytics, le monde de la voile gagne en transparence. Les éléments clés sont l'utilisation du Cloud et des technologies du traitement des données en mémoire vive, le traitement des données de GPS et de mesures de vent en temps réel ainsi que la visualisation de ces contenus sur différents types frontend, accessibles partout. +contentSapSailingAnalytics1=Grâce aux analyses en temps réel des classements de course, vitesses, manœuvres, directions etc., SAP contribue à lever le mystère de la discipline complexe qu''est la voile, et à faciliter son approche. +contentSapSailingAnalytics2=Grâce aux analyses de la solution SAP Sailing Analytics, le monde de la voile gagne en transparence. Les éléments clés sont l''utilisation du Cloud et des technologies du traitement des données en mémoire vive, le traitement des données de GPS et de mesures de vent en temps réel ainsi que la visualisation de ces contenus sur différents types frontend, accessibles partout. sapSailingAnalyticsReadMore=En savoir plus sapSailingRaceManager=SAP Sailing Race Manager -contentSapSailingRaceManager=Grâce à la solution SAP Sailing Race Manager, les organisateurs de courses peuvent être plus efficaces et garder plus facilement la main. Leurs tâches manuelles sont automatisées et simplifiées, tout comme la communication pendant les régates de voile en cours. L'application destinée au comité de course contribue à faciliter la mise en œuvre et la gestion des manifestations de courses pour un déroulement plus souple des compétitions. +contentSapSailingRaceManager=Grâce à la solution SAP Sailing Race Manager, les organisateurs de courses peuvent être plus efficaces et garder plus facilement la main. Leurs tâches manuelles sont automatisées et simplifiées, tout comme la communication pendant les régates de voile en cours. L''application destinée au comité de course contribue à faciliter la mise en œuvre et la gestion des manifestations de courses pour un déroulement plus souple des compétitions. sapSailingRaceManagerReadMore=En savoir plus sapSailInSight=SAP Sail InSight -contentSapSailInSight=Grâce à l'application mobile SAP Sail InSight pour iPhone, iPad et smartphones Android, les participants aux courses à la voile peuvent gérer leur participation dans les régates à tout moment, où qu'ils soient. Cette application se connecte à la solution SAP Sailing Analytics et permet aux compétiteurs de s'inscrire à une régate activée dans SAP Sail InSight, suivre leur place dans la course, avec des indicateurs de performances tels que la vitesse, ou la distance parcourue, et d'analyser leur performance. +contentSapSailInSight=Grâce à l''application mobile SAP Sail InSight pour iPhone, iPad et smartphones Android, les participants aux courses à la voile peuvent gérer leur participation dans les régates à tout moment, où qu''ils soient. Cette application se connecte à la solution SAP Sailing Analytics et permet aux compétiteurs de s''inscrire à une régate activée dans SAP Sail InSight, suivre leur place dans la course, avec des indicateurs de performances tels que la vitesse, ou la distance parcourue, et d''analyser leur performance. sapSailInSightReadMore=En savoir plus sapSailingBuoyPinger=SAP Sailing Buoy Pinger -contentSapSailingBuoyPinger=Grâce à l'application mobile SAP Sailing Buoy Pinger pour smartphones Android, les organisateurs de courses à la voile peuvent simplifier le positionnement des marques de course ainsi que la communication avec les positionneurs des marques, à tout moment, où qu'ils soient. Cette application se connecte à la solution SAP Sailing Analytics et permet aux organisateurs de régates de suivre la position géographique de leurs marques de course. Cette connexion permet en outre aux sportifs participant à la régate d'utiliser l'application mobile SAP Sail InSight. +contentSapSailingBuoyPinger=Grâce à l''application mobile SAP Sailing Buoy Pinger pour smartphones Android, les organisateurs de courses à la voile peuvent simplifier le positionnement des marques de course ainsi que la communication avec les positionneurs des marques, à tout moment, où qu''ils soient. Cette application se connecte à la solution SAP Sailing Analytics et permet aux organisateurs de régates de suivre la position géographique de leurs marques de course. Cette connexion permet en outre aux sportifs participant à la régate d''utiliser l''application mobile SAP Sail InSight. sapSailingBuoyPingerReadMore=En savoir plus postRaceAnalytics=Analyses post-course -contentPostRaceAnalytics1=L'accès aux données collectées lors de manifestations de voile permet aux sportifs de la voile d'analyser et d'évaluer leurs performances, de développer des stratégies et d'optimiser leur navigation. -contentPostRaceAnalytics2=Les solutions SAP Business Analytics fournissent aux sportifs de la voile comme aux entraîneurs, amateurs et média des outils pour parcourir et analyser des données historiques de nombreuses régates et courses. Grâce à la puissance de SAP HANA, des modèles de performance se détachent, des tendances et profils de sportifs de la voile se dessinent de manière simple, rapide et efficace afin d'optimiser leurs propres performances et de développer des stratégies porteuses de succès pour les régates à venir. +contentPostRaceAnalytics1=L''accès aux données collectées lors de manifestations de voile permet aux sportifs de la voile d''analyser et d''évaluer leurs performances, de développer des stratégies et d''optimiser leur navigation. +contentPostRaceAnalytics2=Les solutions SAP Business Analytics fournissent aux sportifs de la voile comme aux entraîneurs, amateurs et média des outils pour parcourir et analyser des données historiques de nombreuses régates et courses. Grâce à la puissance de SAP HANA, des modèles de performance se détachent, des tendances et profils de sportifs de la voile se dessinent de manière simple, rapide et efficace afin d''optimiser leurs propres performances et de développer des stratégies porteuses de succès pour les régates à venir. strategySimulator=Simulateur de stratégies -contentStrategySimulator=Opter pour la bonne stratégie peut procurer un avantage significatif pendant une course. Le simulateur de stratégies simplifie la détermination de la meilleure stratégie de navigation pour différentes conditions de vent et courants d'eau. Comme les données de vent et de courant peuvent être modifiées directement au cours de la simulation, la solidité d'une stratégie peut être facilement évaluée même en cas de conditions météorologiques incertaines. +contentStrategySimulator=Opter pour la bonne stratégie peut procurer un avantage significatif pendant une course. Le simulateur de stratégies simplifie la détermination de la meilleure stratégie de navigation pour différentes conditions de vent et courants d''eau. Comme les données de vent et de courant peuvent être modifiées directement au cours de la simulation, la solidité d''une stratégie peut être facilement évaluée même en cas de conditions météorologiques incertaines. strategySimulatorReadMore=En savoir plus impressum=Mentions légales lastFix=Dernier point -filterDeviceMappings=Filtrer des mappages d'appareils +filterDeviceMappings=Filtrer des mappages d''appareils raceStartAnalysis=Analyse du départ de la course buoyZoneRadiusInHullLengths=Rayon de zone de bouée en longueur de coques (par exemple 2, ou 3) incorrectValueForRegattaBuoyZoneRadiusInHullLengths=Valeur erronée pour le rayon de zone de bouée en longueur de coques importCompetitors=Importer des concurrents -chooseWhichCompetitorsShouldBeImported=Sélectionnez des concurrents à importer sur la gauche. La sélection d'un concurrent individuel affiche sur la droite le ou les concurrent(s) existant(s) appartenant à la même entité. Pour utiliser un concurrent existant, sélectionnez-le. Une fois le mappage terminé, sélectionnez tous les concurrents que vous souhaitez importer dans la table sur la gauche, et appuyez sur OK. Notez que vous pouvez trier les tables en cliquant ou touchant les intitulés des colonnes. +chooseWhichCompetitorsShouldBeImported=Sélectionnez des concurrents à importer sur la gauche. La sélection d''un concurrent individuel affiche sur la droite le ou les concurrent(s) existant(s) appartenant à la même entité. Pour utiliser un concurrent existant, sélectionnez-le. Une fois le mappage terminé, sélectionnez tous les concurrents que vous souhaitez importer dans la table sur la gauche, et appuyez sur OK. Notez que vous pouvez trier les tables en cliquant ou touchant les intitulés des colonnes. existingCompetitors=Concurrents existants importedCompetitors=Concurrents à importer hasMatches=Correspondances disponibles filterImportedCompetitorsByNameSailRaceFleet=Filtrer des concurrents à importer par nom, numéro de voile, course ou flotte -errorLoadingCompetitorImportProviders=Erreur lors du chargement des fournisseurs d'importation de concurrents : {0} -errorLoadingCompetitorImportDescriptors=Erreur lors du chargement des descripteurs d'importation de concurrents : {0} -couldNotSaveCompetitorRegistrations=Impossible d'enregistrer les inscriptions des concurrents : {0} +errorLoadingCompetitorImportProviders=Erreur lors du chargement des fournisseurs d''importation de concurrents : {0} +errorLoadingCompetitorImportDescriptors=Erreur lors du chargement des descripteurs d''importation de concurrents : {0} +couldNotSaveCompetitorRegistrations=Impossible d''enregistrer les inscriptions des concurrents : {0} searchTagForImportedCompetitorPlaceholder=Utilisez par exemple le nom de la course et de la flotte. version=Version : {0} -replicables=Réplication d'objets en cours +replicables=Réplication d''objets en cours set=Définit eventRegattaRacesLegendWind=Nombre de capteurs de vent eventRegattaRacesLegendVideo=Nombre de flux vidéo diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties index 9a7461bb14e..7f5bfdbf0ea 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties @@ -450,6 +450,8 @@ scoringSchemeHighPointFirstGetsTenOrEight=高得点方式、1 位が 10 点 (ま scoringSchemeHighPointFirstGetsTenOrEightDescription=得点数によるスコアです。1 位が 10 点、2 位が 9 点などと得点します。同点となった場合は、より多くのレースで勝者となった競技者を上位とします。それでも同順位となる場合には、最終レースでの得点でのランクで順位を決定します。 scoringSchemeHighPointFirstGetsTwelveOrEight=高得点方式、1 位が 12 点 (または 8 点) scoringSchemeHighPointFirstGetsTwelveOrEightDescription=得点数によるスコアです。1 位が 12 点、2 位が 11 点などと得点します。同点となった場合は、(各競技者のレース得点を高い方から比較して) 最多得点の競技者を上位とします。それでも同順位となる場合には、最終レースでの得点でのランクで順位を決定します。 +scoringSchemeHighPointFirstGetsTwelveOrEight2017=High Point ESS 2017, winner gets 12 points (or 8) +scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored. scoringSystem=得点方式 createFlexibleLeaderboard=フレキシブルリーダーボード登録 createRegattaLeaderboard=レガッタリーダーボード登録 @@ -748,7 +750,7 @@ addSeries=シリーズ追加 regattaDefinesResultDiscardingRules=レガッタにより結果取消ルールを定義 startsWithZeroScore=セロスコアでシリーズ開始 masterDataImportPanel=マスタデータインポート -importSuccess=成功\n{0} リーダーボードグループ、{1} リーダーボード、{2} イベント、{3} レガッタを登録しました。 +importSuccess=成功\n{0} リーダーボードグループ、{1} リーダーボード、{2} イベント、{3} レガッタを登録しました。. TODO {4} importSuccessOverwriteInfo=以下のレガッタを上書きするには、以下のレースを再追跡する必要があります: regattaOverviewConfiguration=レガッタ概要設定 firstRaceIsNonDiscardableCarryForward=取消不可の持ち越しがあるスタート @@ -1412,7 +1414,6 @@ cantDisplayDataOfType={0} タイプのデータは表示できません。 shownDecimals=小数点表示 openFullscreenView=全画面ビューを開く closeFullscreenView=全画面ビューを閉じる -progress=進行 videosCount={0,number} 動画 videosCount[one]={0,number} 動画 photosCount={0,number} 写真 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties index e3be9b77bf3..0c198ad7af3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties @@ -748,7 +748,7 @@ addSeries=Adicionar série regattaDefinesResultDiscardingRules=A regata define as regras de descarte do resultado startsWithZeroScore=A série começa com a pontuação zero masterDataImportPanel=Importação de dados mestre -importSuccess=Êxito\nCriado(s) {0} grupo(s) de painéis de classificação e {1} painel(éis) de classificação e {2} evento(s) e {3} regata(s). +importSuccess=Êxito\nCriado(s) {0} grupo(s) de painéis de classificação e {1} painel(éis) de classificação e {2} evento(s) e {3} regata(s). TODO {4} importSuccessOverwriteInfo=Foi necessário substituir as seguintes regatas, é necessário rastrear novamente suas corridas. regattaOverviewConfiguration=Configuração de síntese de regata firstRaceIsNonDiscardableCarryForward=Começa com transferência não descartável diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index bde050ef340..815e6886218 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -450,6 +450,8 @@ scoringSchemeHighPointFirstGetsTenOrEight=Высокий балл, победи scoringSchemeHighPointFirstGetsTenOrEightDescription=Оценка в баллах. Победитель получает 10 баллов, 2-й — 9 баллов, .... Равенство разрешается в пользу участника, имеющего больше побед в гонках. Если равенство сохраняется, оно разрешается по рангу в последней гонке. scoringSchemeHighPointFirstGetsTwelveOrEight=Высокий балл, победитель получает 12 баллов (или 8) scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Оценка в баллах. Победитель получает 12 баллов, 2-й — 11 баллов, .... Равенство разрешается в пользу участника с наивысшей оценкой. Если равенство сохраняется, оно разрешается по рангу в последней гонке. +scoringSchemeHighPointFirstGetsTwelveOrEight2017=High Point ESS 2017, winner gets 12 points (or 8) +scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored. scoringSystem=Система оценок createFlexibleLeaderboard=Создать гибкую таблицу лидеров createRegattaLeaderboard=Создать таблицу лидеров регаты @@ -1412,7 +1414,6 @@ cantDisplayDataOfType=Невозможно отобразить данные т shownDecimals=Отображаемые десятичные разряды openFullscreenView=Открыть полноэкранный режим closeFullscreenView=Закрыть полноэкранный режим -progress=Ход выполнения videosCount={0,number} видео videosCount[one]={0,number} видео photosCount={0,number} фото diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties index 266e99c2e20..52e62350ad4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties @@ -450,6 +450,8 @@ scoringSchemeHighPointFirstGetsTenOrEight=高分,获胜者得 10 分(或 8 scoringSchemeHighPointFirstGetsTenOrEightDescription=得分。 获胜者得 10 分、第 2 名 9 分、.... 以赢得最多比赛轮次的参赛队取得胜利,如果仍有平局,则以最后一个比赛轮次的名次打破平局。 scoringSchemeHighPointFirstGetsTwelveOrEight=高分,获胜者得 12 分(或 8 分) scoringSchemeHighPointFirstGetsTwelveOrEightDescription=得分。获胜者得 12 分、第 2 名 11 分、.... 得分最高的参赛队取得胜利,如果仍有平局,则以最后一个比赛轮次的名次打破平局。 +scoringSchemeHighPointFirstGetsTwelveOrEight2017=High Point ESS 2017, winner gets 12 points (or 8) +scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored. scoringSystem=记分系统 createFlexibleLeaderboard=创建灵活的积分榜 createRegattaLeaderboard=创建比赛积分榜 @@ -748,7 +750,7 @@ addSeries=添加系列 regattaDefinesResultDiscardingRules=比赛定义结果作废规则 startsWithZeroScore=系列从零分开始 masterDataImportPanel=主数据导入 -importSuccess=成功\n已创建{0}个积分榜分组、{1}个积分榜、{2}个活动和{3}场比赛。 +importSuccess=成功\n已创建{0}个积分榜分组、{1}个积分榜、{2}个活动和{3}场比赛。. TODO {4} importSuccessOverwriteInfo=需要覆盖后续比赛,需要重新跟踪比赛轮次: regattaOverviewConfiguration=比赛总览配置 firstRaceIsNonDiscardableCarryForward=从不可作废的得分开始 @@ -1412,7 +1414,6 @@ cantDisplayDataOfType=无法显示类型为{0}的数据 shownDecimals=显示小数 openFullscreenView=打开全屏视图 closeFullscreenView=关闭全屏视图 -progress=进度 videosCount={0,number} 个视频 videosCount[one]={0,number} 个视频 photosCount={0,number} 张照片 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPositionPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPositionPanel.java index e7967e39ee9..6e3fdb34f4a 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPositionPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPositionPanel.java @@ -563,8 +563,8 @@ public class EditMarkPositionPanel extends AbstractRaceChart i onResize(); } - private void loadData(final Date from, final Date to) { - if (selectedRaceIdentifier != null && from != null && to != null && marks == null) { + private void loadData() { + if (selectedRaceIdentifier != null && marks == null) { setWidget(chart); showLoading(stringMessages.loadingMarkFixes()); markPositionService.getMarksInTrackedRace(raceIdentifierToLeaderboardRaceColumnAndFleetMapper.getLeaderboardNameAndRaceColumnNameAndFleetName(selectedRaceIdentifier), @@ -814,7 +814,7 @@ public class EditMarkPositionPanel extends AbstractRaceChart i @Override public void timeChanged(Date newTime, Date oldTime) { if (isVisible()) { - loadData(timeRangeWithZoomProvider.getFromTime(), timeRangeWithZoomProvider.getToTime()); + loadData(); updateTimePlotLine(newTime); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LegColumn.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LegColumn.java index 49f88bcf562..7946b7f1697 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LegColumn.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LegColumn.java @@ -175,7 +175,7 @@ public class LegColumn extends ExpandableSortableColumn { protected String getTitle(LeaderboardRowDTO row) { String resultString = null; LegEntryDTO entry = getLegEntry(row); - if (entry != null) { + if (entry != null && entry.numberOfManeuvers != null) { StringBuilder result = new StringBuilder(); if (entry.numberOfManeuvers.get(ManeuverType.TACK) != null) { result.append(entry.numberOfManeuvers.get(ManeuverType.TACK)); @@ -212,7 +212,8 @@ public class LegColumn extends ExpandableSortableColumn { result.append(getFormatter().format(fieldValue)); } LegEntryDTO entry = getLegEntry(row); - if (entry != null && entry.numberOfManeuvers.get(ManeuverType.PENALTY_CIRCLE) != null && (int) entry.numberOfManeuvers.get(ManeuverType.PENALTY_CIRCLE) != 0) { + if (entry != null && entry.numberOfManeuvers != null && + entry.numberOfManeuvers.get(ManeuverType.PENALTY_CIRCLE) != null && (int) entry.numberOfManeuvers.get(ManeuverType.PENALTY_CIRCLE) != 0) { result.append(" ("); result.append(entry.numberOfManeuvers.get(ManeuverType.PENALTY_CIRCLE)); result.append("P)"); @@ -227,7 +228,7 @@ public class LegColumn extends ExpandableSortableColumn { if (entry != null) { for (ManeuverType maneuverType : new ManeuverType[] { ManeuverType.TACK, ManeuverType.JIBE, ManeuverType.PENALTY_CIRCLE }) { - if (entry.numberOfManeuvers.get(maneuverType) != null) { + if (entry.numberOfManeuvers != null && entry.numberOfManeuvers.get(maneuverType) != null) { if (result == null) { result = (double) entry.numberOfManeuvers.get(maneuverType); } else { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ManeuverCountRaceColumn.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ManeuverCountRaceColumn.java index 5937c7bb23f..c4283fda80f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ManeuverCountRaceColumn.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ManeuverCountRaceColumn.java @@ -106,7 +106,7 @@ public class ManeuverCountRaceColumn extends ExpandableSortableColumn im if (legDetail != null) { if (legDetail.averageManeuverLossInMeters != null) { for (ManeuverType maneuverType : maneuverTypes) { - final Integer maneuverCount = legDetail.numberOfManeuvers.get(maneuverType); + final Integer maneuverCount = legDetail.numberOfManeuvers==null?null:legDetail.numberOfManeuvers.get(maneuverType); if (maneuverCount != null && maneuverCount != 0) { totalLossInMeters += legDetail.averageManeuverLossInMeters.get(maneuverType) * maneuverCount; count += maneuverCount; @@ -124,7 +124,7 @@ public class ManeuverCountRaceColumn extends ExpandableSortableColumn im if (row != null && row.legDetails != null) { for (LegEntryDTO legDetail : row.legDetails) { if (legDetail != null) { - if (legDetail.numberOfManeuvers.get(maneuverType) != null) { + if (legDetail.numberOfManeuvers != null && legDetail.numberOfManeuvers.get(maneuverType) != null) { if (totalNumberOfManeuvers == null) { totalNumberOfManeuvers = (double) legDetail.numberOfManeuvers.get(maneuverType); } else { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ScoringSchemeTypeFormatter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ScoringSchemeTypeFormatter.java index b56b806e5de..83a019ae966 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ScoringSchemeTypeFormatter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ScoringSchemeTypeFormatter.java @@ -36,6 +36,8 @@ public class ScoringSchemeTypeFormatter { return stringMessages.scoringSchemeHighPointFirstGetsTenOrEight(); case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT: return stringMessages.scoringSchemeHighPointFirstGetsTwelveOrEight(); + case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017: + return stringMessages.scoringSchemeHighPointFirstGetsTwelveOrEight2017(); case LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07: return stringMessages.scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07(); case LOW_POINT_LEAGUE_OVERALL: @@ -52,6 +54,8 @@ public class ScoringSchemeTypeFormatter { return stringMessages.scoringSchemeHighPointFirstGetsTenOrEightDescription(); case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT: return stringMessages.scoringSchemeHighPointFirstGetsTwelveOrEightDescription(); + case HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017: + return stringMessages.scoringSchemeHighPointFirstGetsTwelveOrEight2017Description(); case HIGH_POINT_ESS_OVERALL: return stringMessages.scoringSchemeHighPointEssOverallDescription(); case HIGH_POINT_ESS_OVERALL_12: diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/masterdataimport/MasterDataImportPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/masterdataimport/MasterDataImportPanel.java index 2003f3ee495..1ac002d0dc7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/masterdataimport/MasterDataImportPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/masterdataimport/MasterDataImportPanel.java @@ -32,6 +32,7 @@ import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount; import com.sap.sailing.gwt.ui.client.EventsRefresher; import com.sap.sailing.gwt.ui.client.LeaderboardGroupsRefresher; import com.sap.sailing.gwt.ui.client.LeaderboardsRefresher; +import com.sap.sailing.gwt.ui.client.MediaTracksRefresher; import com.sap.sailing.gwt.ui.client.RegattaRefresher; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -53,6 +54,7 @@ public class MasterDataImportPanel extends VerticalPanel { private final EventsRefresher eventRefresher; private final LeaderboardsRefresher leaderboardsRefresher; private final LeaderboardGroupsRefresher leaderboardGroupsRefresher; + private final MediaTracksRefresher mediaTracksRefresher; private CheckBox compressSwitch; private CheckBox exportWindSwitch; private CheckBox exportDeviceConfigsSwitch; @@ -60,13 +62,14 @@ public class MasterDataImportPanel extends VerticalPanel { public MasterDataImportPanel(StringMessages stringMessages, SailingServiceAsync sailingService, RegattaRefresher regattaRefresher, EventsRefresher eventsRefresher, LeaderboardsRefresher leaderboardsRefresher, - LeaderboardGroupsRefresher leaderboardGroupsRefresher) { + LeaderboardGroupsRefresher leaderboardGroupsRefresher, MediaTracksRefresher mediaTracksRefresher) { this.sailingService = sailingService; this.stringMessages = stringMessages; this.regattaRefresher = regattaRefresher; this.eventRefresher = eventsRefresher; this.leaderboardsRefresher = leaderboardsRefresher; this.leaderboardGroupsRefresher = leaderboardGroupsRefresher; + this.mediaTracksRefresher = mediaTracksRefresher; HorizontalPanel serverAddressPanel = new HorizontalPanel(); serverAddressPanel.add(new Label(stringMessages.importRemoteHost())); @@ -204,6 +207,7 @@ public class MasterDataImportPanel extends VerticalPanel { int leaderboardGroupsCreated = creationCount.getLeaderboardGroupCount(); int eventsCreated = creationCount.getEventCount(); int regattasCreated = creationCount.getRegattaCount(); + int mediaTracksImported = creationCount.getMediaTrackCount(); if (regattasCreated > 0) { regattaRefresher.fillRegattas(); } @@ -216,9 +220,12 @@ public class MasterDataImportPanel extends VerticalPanel { if (leaderboardsCreated > 0) { leaderboardsRefresher.fillLeaderboards(); } + if (mediaTracksImported > 0) { + mediaTracksRefresher.loadMediaTracks(); + } Set overwrittenRegattas = creationCount.getOverwrittenRegattaNames(); showSuccessAlert(leaderboardsCreated, leaderboardGroupsCreated, eventsCreated, regattasCreated, - overwrittenRegattas); + mediaTracksImported, overwrittenRegattas); changeButtonStateAccordingToApplicationState(); } @@ -251,10 +258,10 @@ public class MasterDataImportPanel extends VerticalPanel { } protected void showSuccessAlert(int leaderboardsCreated, int leaderboardGroupsCreated, int eventsCreated, - int regattasCreated, Set overwrittenRegattas) { + int regattasCreated, int mediaTracksImported, Set overwrittenRegattas) { StringBuffer buffer = new StringBuffer(); buffer.append(stringMessages.importSuccess(leaderboardGroupsCreated, leaderboardsCreated, eventsCreated, - regattasCreated)); + regattasCreated, mediaTracksImported)); if (overwrittenRegattas.size() > 0) { buffer.append("\n\n" + stringMessages.importSuccessOverwriteInfo() + "\n"); for (String regattaName : overwrittenRegattas) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java index cdd955b72d2..1b2bed6bc56 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java @@ -114,7 +114,7 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint { createErrorPage(getStringMessages().noSuchEvent()); } if (leaderboardGroupName != null) { - if(!raceboardData.isValidLeaderboardGroup()) { + if (!raceboardData.isValidLeaderboardGroup()) { createErrorPage(getStringMessages().leaderboardNotContainedInLeaderboardGroup(leaderboardName, leaderboardGroupName)); return; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 3c2b0ca9c7b..9af5775ee3e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -232,6 +232,7 @@ import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl; +import com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl.PreciseCompactPosition; import com.sap.sailing.domain.igtimiadapter.Account; import com.sap.sailing.domain.igtimiadapter.IgtimiConnection; import com.sap.sailing.domain.igtimiadapter.IgtimiConnectionFactory; @@ -467,6 +468,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.TimeRangeImpl; import com.sap.sse.common.mail.MailException; import com.sap.sse.common.media.MimeType; +import com.sap.sse.filestorage.FileStorageManagementService; import com.sap.sse.filestorage.FileStorageService; import com.sap.sse.filestorage.InvalidPropertiesException; import com.sap.sse.gwt.client.ServerInfoDTO; @@ -739,7 +741,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public Pair makePersonDTOSerializableAndDeserializableDummy(PersonDTO dummy, CountryCode ccDummy) { return null; } + public Pair serializationDummy(PersonDTO dummy, CountryCode ccDummy, PreciseCompactPosition preciseCompactPosition) { return null; } /** * If date is null, the {@link LiveLeaderboardUpdater} for the @@ -5179,6 +5181,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S numberOfWindFixesImportedPerRace.put(key, i+resultForAccount.getValue()); } } + for (final TrackedRace trackedRace : trackedRaces) { + // update polar sheets: + getService().getPolarDataService().insertExistingFixes(trackedRace); + } return numberOfWindFixesImportedPerRace; } @@ -5372,9 +5378,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public void revokeMarkDefinitionEventInRegattaLog(String leaderboardName, MarkDTO markDTO) throws DoesNotHaveRegattaLogException { RegattaLog regattaLog = getRegattaLogInternal(leaderboardName); - final List regattaLogDefineMarkEvents = new AllEventsOfTypeFinder<>(regattaLog, /* only unrevoked */ true, RegattaLogDefineMarkEvent.class).analyze(); - RegattaLogDefineMarkEvent eventToRevoke = null; for (RegattaLogEvent event : regattaLogDefineMarkEvents) { RegattaLogDefineMarkEvent defineMarkEvent = (RegattaLogDefineMarkEvent) event; @@ -5383,7 +5387,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S break; } } - regattaLog.revokeDefineMarkEventAndRelatedDeviceMappings(eventToRevoke, getService().getServerAuthor(), logger); } @@ -5908,10 +5911,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S revoke = true; create = false; } else { - boolean same = newZeroBasedIndexOfSuppressedMarkPassing == oldSuppressedMarkPassingEvent - .getZeroBasedIndexOfFirstSuppressedWaypoint(); - create = !same; - revoke = !same; + boolean equal = Util.equalsWithNull(newZeroBasedIndexOfSuppressedMarkPassing, + oldSuppressedMarkPassingEvent.getZeroBasedIndexOfFirstSuppressedWaypoint()); + create = !equal; + revoke = !equal; } } if (revoke) { @@ -5992,9 +5995,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public FileStorageServiceDTO[] getAvailableFileStorageServices(String localeInfoName) { List serviceDtos = new ArrayList<>(); - for (FileStorageService s : getService().getFileStorageManagementService().getAvailableFileStorageServices()) { - serviceDtos.add(FileStorageServiceDTOUtils.convert(s, getLocale(localeInfoName))); - } + final FileStorageManagementService fileStorageManagementService = getService().getFileStorageManagementService(); + if (fileStorageManagementService != null) { + for (FileStorageService s : fileStorageManagementService.getAvailableFileStorageServices()) { + serviceDtos.add(FileStorageServiceDTOUtils.convert(s, getLocale(localeInfoName))); + } + } return serviceDtos.toArray(new FileStorageServiceDTO[0]); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html index a19e3c66b4c..99606e16b36 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html @@ -4,6 +4,18 @@

What's New - SAP Sailing Analytics

+
March 2017
+
    +
  • The SAP Sailing Analytics are now also available in French, Portugese, as well as Spanish. + Find the language chooser in the lower right corner of the footer, or when signed in, go to your user + profile and set your preferred language. +
  • +
  • The application's locale now switches based on the client's "Accept-Language" HTTP header field. + This means that the application in all its parts will show in the user's default language if + supported, defaulting to English otherwise. +
  • +
+
February 2017

Enums

    +
  • DataSource
  • EventType
  • RaceCompetitorStatusType
  • RaceStatusType
  • diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/package-summary.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/package-summary.html index 705061a553b..552aec60d85 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/package-summary.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/package-summary.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api.event - + @@ -154,31 +154,38 @@ +DataSource + +
    + The datasource used to load data
    + + + EventType
    The type of the event, according with the EventManager
    - + RaceCompetitorStatusType
    Enumeration representing all the possible values for the competitor status.
    - + RaceStatusType
    Values for race status.
    - + RaceVisibilityType
    Values for race visitility.
    - + StartTimeType
    Type of start time to use.
    diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/package-tree.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/package-tree.html index d6fd978a7df..4d205683748 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/package-tree.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/package-tree.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api.event Class Hierarchy - + @@ -150,9 +150,10 @@
    • java.lang.Enum<E> (implements java.lang.Comparable<T>, java.io.Serializable) diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadata.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadata.html index 834ff2455a8..b1ba5c589db 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadata.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadata.html @@ -2,9 +2,9 @@ - + IMetadata - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadataContainer.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadataContainer.html index 8ba84079035..7f6bf296902 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadataContainer.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadataContainer.html @@ -2,9 +2,9 @@ - + IMetadataContainer - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadataFactory.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadataFactory.html index 3c99bf4449a..15625e8087a 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadataFactory.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IMetadataFactory.html @@ -2,9 +2,9 @@ - + IMetadataFactory - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IPropertiesContainer.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IPropertiesContainer.html index 4d5296f5c4e..8ecf4ed5d9f 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IPropertiesContainer.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/IPropertiesContainer.html @@ -2,9 +2,9 @@ - + IPropertiesContainer - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-frame.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-frame.html index 6cb897f6b81..92ab8c55049 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-frame.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-frame.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api.metadata - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-summary.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-summary.html index df5d00e3416..a2f64e7dc17 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-summary.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-summary.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api.metadata - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-tree.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-tree.html index f0442a55101..96dd0264c6e 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-tree.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/metadata/package-tree.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api.metadata Class Hierarchy - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-frame.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-frame.html index 719bd795d36..e4d027a7e24 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-frame.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-frame.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-summary.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-summary.html index 7ba2e754d9f..bdaa39ea785 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-summary.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-summary.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-tree.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-tree.html index c5132f18a9d..c27df950d6d 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-tree.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/package-tree.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api Class Hierarchy - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControl.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControl.html index a49c7d91837..975c21ad224 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControl.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControl.html @@ -2,9 +2,9 @@ - + IControl - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControlPoint.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControlPoint.html index 26208c5fb29..20ae94284c8 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControlPoint.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControlPoint.html @@ -2,9 +2,9 @@ - + IControlPoint - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControlRoute.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControlRoute.html index 008f085d385..29dfea9e78d 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControlRoute.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IControlRoute.html @@ -2,9 +2,9 @@ - + IControlRoute - + @@ -161,6 +161,13 @@ extends +
      • diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathRoute.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathRoute.html index 03443c48ed6..746a5a9acdf 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathRoute.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathRoute.html @@ -2,9 +2,9 @@ - + IPathRoute - + @@ -162,6 +162,13 @@ extends +
        • diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathRouteFactory.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathRouteFactory.html index fb278a18d87..c9914b80aa5 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathRouteFactory.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathRouteFactory.html @@ -2,9 +2,9 @@ - + IPathRouteFactory - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathSegment.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathSegment.html index ef558c6d6bb..6e21036c367 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathSegment.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IPathSegment.html @@ -2,9 +2,9 @@ - + IPathSegment - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IRoute.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IRoute.html index fe9de82bb9d..b72a4445e96 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IRoute.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/IRoute.html @@ -2,9 +2,9 @@ - + IRoute - + @@ -18,6 +18,12 @@ catch(err) { } //--> +var methods = {"i0":6}; +var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"]}; +var altColor = "altColor"; +var rowColor = "rowColor"; +var tableTab = "tableTab"; +var activeTableTab = "activeTableTab";
@@ -125,6 +131,19 @@ extends

Method Summary

+ + + + + + + + + + +
All Methods Instance Methods Abstract Methods 
Modifier and TypeMethod and Description
IExtentgetExtent() +
Gets the extent of the route
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getExtent

        +
        IExtent getExtent()
        +
        Gets the extent of the route
        +
        +
        Returns:
        +
        the extent
        +
        +
      • +
      +
    • +
    +
  • +
+
@@ -215,13 +262,13 @@ extends Nested | 
  • Field | 
  • Constr | 
  • -
  • Method
  • +
  • Method
  • diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/ISegment.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/ISegment.html index b4a441d2e62..e68772d0744 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/ISegment.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/ISegment.html @@ -2,9 +2,9 @@ - + ISegment - + @@ -18,7 +18,7 @@ catch(err) { } //--> -var methods = {"i0":6}; +var methods = {"i0":6,"i1":6}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -134,6 +134,12 @@ extends Returns the coordinates that the segment is based on.
    + +IExtent +getExtent() +
    Gets the segment's extent
    + +
    • @@ -173,7 +179,7 @@ extends -
        + + + + +
          +
        • +

          getExtent

          +
          IExtent getExtent()
          +
          Gets the segment's extent
          +
          +
          Returns:
          +
          the extent
          +
          +
        • +
    • diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-frame.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-frame.html index 7daa3ba8858..c4e217b2101 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-frame.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-frame.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api.route - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-summary.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-summary.html index 1774f325c9e..d61cb339083 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-summary.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-summary.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api.route - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-tree.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-tree.html index 3045d7048ec..bbea61e7c24 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-tree.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/route/package-tree.html @@ -2,9 +2,9 @@ - + com.tractrac.model.lib.api.route Class Hierarchy - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/spatial/ICoordinate.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/spatial/ICoordinate.html index 8da36066ec6..965a1c4ba40 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/spatial/ICoordinate.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/spatial/ICoordinate.html @@ -2,9 +2,9 @@ - + ICoordinate - + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/spatial/ICoordinateSequence.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/spatial/ICoordinateSequence.html index fc756958d37..f4b2ec55bb2 100755 --- a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/spatial/ICoordinateSequence.html +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/spatial/ICoordinateSequence.html @@ -2,9 +2,9 @@ - + ICoordinateSequence - + @@ -49,7 +49,7 @@ var activeTableTab = "activeTableTab";